路漫漫其修远兮
吾将上下而求索

docker学习:镜像操作和dockerfile

镜像拉取
docker pull [选项] [Docker	Registry地址]<仓库名>:<标签>
命令中没有给出 Docker Registry 地址,因此将会从Docker Hub 获取镜像
[root@localhost ~]#docker pull ubuntu:14.04

docker images 可能用到的选项
-q, --quiet    只显示id号,Only show numeric IDs
-f, --filter   过滤,根据条件过滤镜像
--filter配合-q产生出指定范围的ID列表,然后送给另一个docker命令作为参数

列出已经下载的镜像
[root@localhost ~]#docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              14.04               c69811d4e993        13 days ago         188MB
centos              latest              328edcd84f1b        2 weeks ago         193MB

当有新版centos,重新pull的时候,这版本的centos就会变成虚悬镜像,虚悬镜像已经失去价值,可以删除
显示虚悬镜像
[root@localhost ~]#docker images -f dangling=true
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

删除虚悬镜像
docker rmi $(docker images -q -f dangling=true)

显示镜像的中间层,docker是一层一层加起来的,不可删除,有用,-a选项可以查看
-a, --all             Show all images (default hides intermediate images)

[root@localhost ~]#docker images -a
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              14.04               c69811d4e993        13 days ago         188MB
centos              latest              328edcd84f1b        2 weeks ago         193MB


如果镜像太多,只想列出部分镜像
根据仓库名列出镜像
[root@localhost ~]#docker images ubuntu
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              14.04               c69811d4e993        13 days ago         188MB

只显示id号
-q, --quiet           Only show numeric IDs
[root@localhost ~]#docker images -q
c69811d4e993
328edcd84f1b

--filter配合-q产生出指定范围的ID列表,然后送给另一个docker命令作为参数
[root@master ~]#docker images --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}"
IMAGE ID            REPOSITORY          TAG
ff426288ea90        centos              latest



根据运行的容器 定制为需要的镜像

当需要将上面在docker中修改的内容重新打包为一个层,构建成新的镜像
[root@localhost ~]#docker commit -h
docker commit [选项] <容器ID或容器名> [<仓库名>[:<标签>]]

[root@localhost ~]#docker run --name mycentos -it centos bash
[root@88ebb52ce85a /]# mkdir abc
[root@88ebb52ce85a /]# cd abc/
[root@88ebb52ce85a abc]# ls
[root@88ebb52ce85a abc]# echo docker > file
[root@88ebb52ce85a abc]# exit    
exit
[root@localhost ~]#docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
88ebb52ce85a        centos              "bash"              47 seconds ago      Exited (0) 5 seconds ago                       mycentos
[root@localhost ~]#docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

修改docker里面的文件后,可以使用下面的命令查看修改了什么内容
docker diff webserver 
[root@localhost ~]#docker diff mycentos
C /root
A /root/.bash_history
A /abc
A /abc/ali

下面是语法格式:
docker commit [选项] <容器ID或容器名> [<仓库名>[:<标签>]]
[root@localhost ~]#docker commit --author "contact@andblog.cn" --message "add a file" mycentos centos:v.01
sha256:857b9fefe9cc9844e24af3e0e2d2aa244a06b5f7e0d110ab537c222a0eda0bde
[root@localhost ~]#docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
[root@localhost ~]#docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
88ebb52ce85a        centos              "bash"              3 minutes ago       Exited (0) 2 minutes ago                       mycentos
[root@master ~]#docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
mycentos            v0.1                2b839380ec21        20 seconds ago      207MB
centos              latest              ff426288ea90        3 weeks ago         207MB

docker commit一般不用,因为只有commit的人知道改了什么东西,而且会产生很多多于的东西,一般使用dockerfile




Dockerfile:
	Dockerimages:
		docker commit
		dockerfile:文本文件,镜像文件构建脚本,一系列用于根据基础镜像构建新的镜像文件的专用的指令序列组成
		必须是基于某个已有的基础镜像来进行构建新的镜像文件

一般来说,应该会将Dockerfile置于一个空目录下,或者项目根目录下。如果该目录下没有所需文件,那么应该把所需文件复制一份过来。如果
目录下有些东西确实不希望构建时传给Docker引擎,那么可以用.gitignore一样的语法写一个.dockerignore,该文件是用于剔除不需要作为上下
文传递给Docker引擎的
实际上Dockerfile的文件名并不要求必须为Dockerfile,而且并不要求必须位于上下文目录中,比如可以用-f ../Dockerfile.php		
参数指定某个文件作为Dockerfile   
        
指令:选定基础镜像,安装必要的程序,复制配置文件和数据文件,自动运行的服务,以及要暴露的端口,环境变量等等
命令:docker build
语法格式:指令行,注释行和空白行
		指令行:由指令及指令参数构成
			指令:字符不区分大小写,但约定俗称,要使用全大写,
		注释行:#开头的行,必须单独位于一行中,不能在指令行后面注释,
		空白行:会被忽略

应该将 Dockerfile 置于一个空目录下,或者项目根目录下。如果该目录下没有所需文件,那么应该把所需文件复制一份过来。
下面是一个简单的示例
[root@master ~/file]#cat Dockerfile 
FROM nginx
RUN echo '<h1>hello, Docker!</h1>' > /usr/share/nginx/html/index.html

docker build 参数说明
--rm                      Remove intermediate containers after a successful build (default true)
-t, --tag list                Name and optionally a tag in the 'name:tag' format

[root@master ~/file]#docker build --rm -t nginx:v3 .
Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM nginx
latest: Pulling from library/nginx
e7bb522d92ff: Pull complete 
6edc05228666: Pull complete 
cd866a17e81f: Pull complete 
Digest: sha256:285b49d42c703fdf257d1e2422765c4ba9d3e37768d6ea83d7fe2043dad6e63d
Status: Downloaded newer image for nginx:latest
 ---> 3f8a4339aadd
Step 2/2 : RUN echo '<h1>hello, Docker!</h1>' > /usr/share/nginx/html/index.html
 ---> Running in 4f03b777a4c5
Removing intermediate container 4f03b777a4c5
 ---> 8cffc1211c18
Successfully built 8cffc1211c18
Successfully tagged nginx:v3        

[root@master ~/file]#docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               v3                  8cffc1211c18        3 minutes ago       108MB
mycentos            v0.1                2b839380ec21        25 minutes ago      207MB
centos              latest              ff426288ea90        3 weeks ago         207MB
nginx               latest              3f8a4339aadd        5 weeks ago         108MB
     

指令: 
FROM指令:必须是第一个非注释行,用于指定所用到的基础镜像,
    FROM <Images>[:<tag>]
    FROM <Images>@<digest>
    
    FROM busybox:latest
    FROM centos:6.9 
    注意:尽量不要在一个dockerfile文件中使用多个FROM指令
    下面有很多高质量的镜像资源,可以使用,在这些镜像基础上进行新镜像构建新的镜像,如果没有,官方还有更基础的操作系统镜像来使用
    https://hub.docker.com/explore/
    
    FROM scratch 
    除了选择现有镜像为基础镜像外,Docker还存在一个特殊的镜像,名为scratch。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。
    如果你以scratch为基础镜像的话,意味着你不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在。
    
    
MAINTANIER:用于提供信息的指令,用于让作者提供本人的信息,不限制其出现的位置,但建议紧跟在FROM之后,内容不限
    MAINTANIER <author's detail>                    '
    MAINTANIER andblog.cn Linux Operation
    
COPY:用于从docker主机(宿主机)复制文件到正在创建的映像文件中,
    COPY <src> ... <dest>
    COPY ["<src>",... "<dest>"] #有的文件名中间有空格,为了不让这有空格的文件名识别为两个文件名,可以使用这种方式
    
    <src>:要复制的源文件或目录,支持使用通配符
    <dest>:目标目录,正在创建的镜像文件的文件系统路径,建议使用绝对路径,否则相对WORKDIR而言
    
    所有新复制生成的文件目录的UID和GID均为0
    COPY server.xml /etc/tomcat/server.xml
    COPY *.conf /etc/httpd/conf.d 
    注意:<src>必须是build上下文中的路径,因此,不能使用类似"../somefile"之类的路径
            如果src是目录的话,会递归复制。如果有多个src,包括在src上使用通配符情形,dest必须是目录,而且必须以/结尾
        <dest>如果事先不存在,它将被自动创建,包括父目录
        
ADD:类似于copy指令,额外还支持复制tar格式的文件,以及url路径,
    ADD <src> ... <dest>
    ADD ["<src>",... "<dest>"] #有的文件名中间有空格,为了不让这有空格的文件名识别为两个文件名,可以使用这种方式

    ADD haproxy.cfg /etc/haproxy/haproxy.cfg
    ADD logstash_*.cnf /etc/logstash 
    ADD http://www.abc.com/c.conf /etc/nginx/
    
    以url格式指定的源文件,下载完成后其目标文件的权限为600,
    注意:注意:<src>必须是build上下文中的路径,因此,不能使用类似"../somefile"之类的路径
        如果<src>是url,且<dest>不以/结尾,则<src>指定的文件将被下载并直接创建为<dest>,如果<dest>以/结尾,则url指定文件将被下载至<dest>中,并保留原名
        如果src是一个host本地的文件系统上的tar格式文件,它将被展示为一个目录,行为类似于tar -x,如果通过url下载的文件是tar格式,则不会进行展开
        如果src是目录的话,会递归复制。如果有多个src,包括在src上使用通配符情形,dest必须是目录,而且必须以/结尾
        <dest>如果事先不存在,它将被自动创建,包括父目录
        
ENV:定义环境变量,此些变量可被当前dockerfile文件中的其他指令所调用,调用格式:$valuename或${valuename}
    ENV <key> <value>  #上面的一次只能定义一个变量
    ENV <key>=<value> ,#下面一次可以定义一堆变量,如果value中有空白字符,要使用反斜线转义,或加引号,上面的不用
    
    ENV myname="hehe haha" mydog=andy\ w  \	#最后的反斜线是换行
        mycat=fewf
    ENV myname hehe haha
    
    ENV定义的环境变量在镜像运行的整个过程中一直存在,因此,可以使用inspect命令查看,甚至可以在docker run启动镜像时使用-env选项修改指定变量的值
    也可以当做是宏定义,不想里面多次修改的,都可以设置环境变量代替
    
USER:指定运行镜像时,或者运行dockerfile文件中任何RUN/CMD/ENTERYPOINT指令指定的程序时使用的用户名或者uid
    USER <UID> | <username> #UID应该使用/etc/passwd文件中存在的用户uid,否则docker run可能出错
    
WORKDIR:为dockerfile中所有的RUN/CMD/ENTRYPOINT/COPY/ADD指令指定工作目录的
    WORKDIR <dirpath>
    注意:WORKDIR可出现多次,也可以使用相对路径,此时表示相对于前一个workdir指定的路径,workdir还可以调用由env定义的环境变量的值
    
    WORKDIR /var/log
    WORKDIR $STATEPATH
	
VOLUME:用于目标镜像文件中创建一个挂载点目录,用于挂载主机上的卷或者其他容器的卷
	VOLUME <mountpoint>
	VOLUME ["<mountpoint>",…]

	如果mountpoint路径下事先有文件存在,docker run会在卷挂载完成后将此前此挂载目录下的文件复制到新的挂载点中的卷中

RUN:用于指定docker build命令运行过程中要运行的命令,不是启动dockerfile构建完成的镜像时要运行的命令。
	每个run都会在一个新的层中,建议将多个run放一个中执行,使用&&将各个所需命令串联起来。将之前多个run执行生成的多层,简化为了1层。
	在撰写Dockerfile的时候,要经常提醒自己,这并不是在写Shell脚本,而是在定义每一层该如何构建,一定要确保每一层只添加真正需要添加
	的东西,任何无关的东西都应该在构建完成后清理掉
	RUN <command>
	RUN ["<executeable>","<param>",…]
	RUN ["/bin/bash","-c","<executeable>","<param>","<param>",…]  上面的其实是这个意思
	
	RUN yum install iproute nginx && yum clean all    示例:构建完成后元数据没有用,可以清理掉

CMD:类似于run指令,用于运行程序,二者运行的时间点不同,不是在docker build中运行,是在docker run中运行
	首要目的为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束;不过,cmd指令指定的程序可被docker run命令行参数中指定要
	运行的程序所覆盖,默认的cmd是/bin/bash
	下面是语法格式:
	RUN <command>
	RUN ["<executeable>","<param>","<param>"…]
	RUN ["<param>","<param>",…]  上面的其实是这个意思
	
	第三种为ENTRYPOINT指令指定的程序提供默认的参数
	注意:容器dockerfile中存在多个cmd指令,仅最后一个生效
	
	CMD ["/usr/sbin/httpd","-c","/etc/httpd/conf/httpd.conf"]
	不能用service来启动nginx,正确的做法是直接执行 nginx 可执行文件,并且要求以前台形式运行。比如:
        CMD ["nginx", "-g", "daemon off;"]

ENTRYPOINT指令:类似于CMD指令,但其不会被docker run的命令行参数指定的指令所覆盖,而且这些命令行参数送给ENTRYPOINT指令指定的程序;
	但是,如果运行docker run使用了--entrypoint选项,而此选项的参数可当做要运行的程序覆盖ENTRYPOINT指令指定的程序
	语法格式:
	RUN <command>
	RUN ["<executeable>","<param>",…]

EXPOSE:用于为容器指定要暴露的端口
	语法格式: 
		EXPOSE <port>[/<potocol>] [<port>[/<protocol>]]...
		<protocol>为tcp或者udp二者之一,默认为tcp
	例如:EXPOSE 11211/tcp 11211/udp

ONBUILD:定义触发器,当前dockerfile构建出的镜像被用作基础镜像去构建其他镜像的时候,ONBUILD指令指定的操作才会被执行。
	语法格式:
		ONBUILD <instruction>
	例如: 
		ONBUILD ADD my.cnf /etc/mysql/my.cnf 
		
==============================================='
        
将镜像文件保存为tar文件
docker还提供了 docker load 和 docker save 命令,用以将镜像保存为一个 tar 文件,然后传输到另一个位置上,再加载进来。这是在没有 Docker Registry 时的做法
        
[root@master ~]#docker images nginx:v3
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               v3                  d1d553886f41        2 hours ago         108MB

保存镜像
[root@master ~]#docker save nginx:v3 | gzip > nginx:v3.tar.gz
[root@master ~]#docker rmi nginx:v3
Untagged: nginx:v3
Deleted: sha256:d1d553886f41d1cb76afac9f6ec61fa6d9257eff872b0cf4dd88fe6c0e60e15f

将镜像复制到其他机器,加载镜像
[root@master ~]#docker load -i nginx\:v3.tar.gz 
781dc21f6702: Loading layer [==================================================>]  52.96MB/52.96MB
4b20cde81d42: Loading layer [==================================================>]  3.584kB/3.584kB
Loaded image: nginx:v3
[root@master ~]#docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               v3                  d1d553886f41        2 hours ago         108MB
centos              latest              ff426288ea90        3 weeks ago         207MB
nginx               latest              3f8a4339aadd        5 weeks ago         108MB
debian              stretch-slim        9a091084b515        7 weeks ago         55.3MB
        
        

删除镜像文件

docker rmi [选项] <镜像1> [<镜像2> ...]
注意docker rm 为删除容器,不能混淆
其中, <镜像> 可以是 镜像短	ID 、 镜像长 ID 、 镜像名 或者 镜像摘要	

查看生成镜像的层数
docker history haror.andblog.com/public/centos:7-beta


给镜像重新打标签,并推送到harbor上面
docker tag SOURCE_IMAGE[:TAG] harbor.andblog.com/project/IMAGE[:TAG]
docker push harbor.andblog.com/project/IMAGE[:TAG]

未经允许不得转载:江哥架构师笔记 » docker学习:镜像操作和dockerfile

分享到:更多 ()

评论 抢沙发

评论前必须登录!