docker之dockerfile自动构建镜像

Dockerfile 构建镜像常用指令

Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指定的内容,就是描述该层应当如何构建。

通过使用build 命令,根据Dockerfile的描述来构建镜像

通过源代码的方式

通过标准输入流的方式

通过源代码的路径:

Dockerfile需要放置在项目的跟目录位置

在构建的时候,Dockerfile client会把整个context打包发送到Docker Server端,然后由server端负责build镜像,在构建成功后,会删除context目录

  docker build -t {镜像名字} {项目的路径可以是相对路径}

通过标准输入流:

通过标准输入流的方式获取Dockerfile的内容

client不会打包上传context目录,因此对于一些ADD、COPY等涉及host本地文件复制的操作不能够支持

  docker build -t {镜像名字} - < Dockerfile路径

使用dockerfile构建镜像步骤

1.手动制作一次镜像

2.根据历史命令来编写dockerfile文件

3.使用dockerfile构键镜像

docker build --network=host -t 镜像名:标签

4.测试镜像

示例nginx

[root@docker01 ~]# mkdir /data/dockerfile/nginx
​
[root@docker01 ~]# cd /data/dockerfile/nginx
​
[root@docker01 /data/dockerfile/nginx]# vim dockerfile
FROM centos:7
RUN rm -rf /etc/yum.repos.d/* \
 && curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo \
 && curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
ADD nginx.repo /etc/yum.repos.d
RUN yum -y install nginx
CMD ["nginx", "-g"," daemon off;"]
​
[root@docker01 /data/dockerfile/nginx]# ll
total 100
-rw-r--r-- 1 root root   319 Jan  9 10:11 dockerfile
-rw-r--r-- 1 root root   398 Jan  9 08:47 nginx.repo
​
[root@docker01 /data/dockerfile/nginx]# docker build --network=host -t centos_nginx:v1 .
[root@docker01 /data/dockerfile/nginx]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
centos_nginx        v1                  ddc845aaedd9        28 minutes ago      347MB
centos              7                   5e35e350aded        8 weeks ago         203MB
​

FROM 指定基础镜像

所谓的定制镜像,必须是以一个镜像为基础,在其上进行定制。一个 Dockerfile 中的 FROM 是必备的指定,并且必须是第一条指令。

FROM {bash镜像}

RUN 执行命令

RUN 指令是用来执行命令行命令的,一个Dockerfile可以包含多个 RUN,按照定义顺序执行。(每运行一个run实际是开启一个容器,只是执行完成后删除容器,只保留镜像,所有最终的镜像也是分层叠放在一起的。)

RUN 支持两种运行格式:

  • shell 格式:

RUN <cmd>,这个会当做/bin/sh -c “cmd” 运行,就像直接在命令行中输入的命令一样。比如上面的:

RUN echo '<h1>Hello, Nginx!</h1>' > /usr/share/nginx/html/index.html
  • exec 格式:

RUN ["可执行文件", "参数1", "参数2", ...],Docker 把它当做json的顺序来解析,必须使用双引号,且可执行文件必须是完整路径。

示例nginx

[root@docker01 /data/dockerfile/nginx]# vim dockerfile
FROM centos:7
RUN rm -rf /etc/yum.repos.d/*
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
RUN curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
RUN yum -y install nginx
CMD ["nginx", "-g"," daemon off;"]
#生成镜像
[root@docker01 /data/dockerfile/nginx]# docker build --network=host -t centos7_nginx:v2 .
#启动进项测试
[root@docker01 /data/dockerfile/nginx]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
centos7_nginx       v2                  be89fe1379e3        22 minutes ago      418MB
centos_nginx        v1                  ddc845aaedd9        2 hours ago         347MB
centos              7                   5e35e350aded        8 weeks ago         203MB
[root@docker01 /data/dockerfile/nginx]# docker run -d -p 80:80 centos7_nginx:v2
c8e5f2c35d75a349840eae203b59d21d3c9ab202b3b3cf77c49d2237bc028ff8

测试访问

file1.png

因为Dockerfile 中的每一个指令都会建立一层,RUN 也不例外,每一个RUN 的行为,就和我们手工创建镜象的过程一样,新建一层,上面的这种写法创建了4层,这样会产生非常臃肿、非常多层的镜像,不仅仅增加了构建部署的时间,也容易出错。上面的Dockerfile正确写法应该如下:

[root@docker01 /data/dockerfile/nginx]# vim dockerfile
FROM centos:7
RUN rm -rf /etc/yum.repos.d/* \
 && curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo \
 && curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo \
 && yum -y install nginx
CMD ["nginx", "-g"," daemon off;"]

这里只是更新yum源安装nginx,实际只是为了安装nginx,这里将四层合成一层更加的一层。

如果需要安装nginx官方的可以参考第一个实例制作即可。只需创建官方源文件copy到对应的保存目录即可。

WORKDIR 指定工作目录

格式:

  • WORKDIR <工作目录路径>

使用 WORKDIR 指令可以来制定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,则会自动创建。相当于cd。

COPY 复制文件

格式:

  • COPY <源路径> ... <目标路径>

  • COPY ["<源路径1>", ... "<目标路径>"]

和 RUN 指令一样,也有两种格式,一种类似于命令行,一种类似于函数调用。

说明:这里测试一个小游戏小鸟飞飞

示例

[root@docker01 /data/dockerfile/nginx]# ll
total 100
-rw-r--r-- 1 root root   292 Jan  9 11:32 dockerfile
-rw-r--r-- 1 root root   398 Jan  9 10:32 nginx.repo
drwxr-xr-x 3 root root    98 Jan  3 19:41 xiaoniao
-rw-r--r-- 1 root root 91985 Jan  8 11:37 xiaoniao.tar.gz
​
[root@docker01 /data/dockerfile/nginx]# vim dockerfile
FROM centos:7
RUN rm -rf /etc/yum.repos.d/* \
 && curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo \
 && curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo \
 && yum -y install nginx
WORKDIR /usr/share/nginx/html
COPY xiaoniao .
CMD ["nginx", "-g"," daemon off;"]
​
[root@docker01 /data/dockerfile/nginx]# docker build --network=host -t centos7_nginx:v4 .
​
[root@docker01 /data/dockerfile/nginx]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
centos7_nginx       v4                  b79afda2fe6f        39 seconds ago      418MB
centos7_nginx       v3                  4a93800b7239        20 minutes ago      418MB
centos7_nginx       v2                  be89fe1379e3        53 minutes ago      418MB
centos_nginx        v1                  ddc845aaedd9        2 hours ago         347MB
centos              7                   5e35e350aded        8 weeks ago         203MB
0 minutes       0.0.0.0:80->80/tcp   nice_franklin
​
[root@docker01 /data/dockerfile/nginx]# docker stop $(docker ps -q)
c8e5f2c35d75
​
[root@docker01 /data/dockerfile/nginx]# docker run -d -p 80:80 centos7_nginx:v4
987610dfb4a6c076a094695bbf382c28c81795e684e4486258d617d6626c6f57
​
[root@docker01 /data/dockerfile/nginx]# docker exec -it 564a5fb1fd91 /bin/bash
[root@564a5fb1fd91 html]# ls
2000.png  404.html  en-US     icons  index.html      poweredby.png
21.js     50x.html  icon.png  img    nginx-logo.png  sound1.mp3

测试访问

[root@docker01 /data/dockerfile/nginx]# vim dockerfile
FROM centos:7
RUN rm -rf /etc/yum.repos.d/* \
 && curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo \
 && curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo \
 && yum -y install nginx
WORKDIR /usr/share/nginx/html
COPY xiaoniao ./xiaoniao
CMD ["nginx", "-g"," daemon off;"]
​
[root@docker01 /data/dockerfile/nginx]# docker build --network=host -t centos7_nginx:v5 .
​
[root@docker01 /data/dockerfile/nginx]# docker run -d -p 81:80 centos7_nginx:v5
​
[root@docker01 /data/dockerfile/nginx]# docker exec -it cdea08555c04 /bin/bash
[root@cdea08555c04 html]# ls
404.html  50x.html  en-US  icons  img  index.html  nginx-logo.png  poweredby.png  xiaoniao

测试访问

file3.png

file4.png

从上面示例可以看出, <目标路径> 可以是容器内的相对路径,如果该路径不存在,会自动在复制文件前创建缺失目录,且<目标路径>也可以是相对路径(工作目录可以用WORKDIR 指令来指定)

如果是拷贝目录, 那么在 <目标地址 >也必须写上 拷贝的目录的名称 。否则是将该目录下的所文件拷贝到目标路径

还需注意一点,使用COPY指令,源文件的各种元数据都会保留,比如读、写、执行权限、文件变更时间等。这个特性对于镜像定制很有用。特别是构建相关的文件都在使用Git进行管理的时候。

ADD 更高级的复制文件

ADD 指令和COPY 的格式和性质基本一致。但是在 COPY 基础上增加了一些功能。

比如 <源路径> 可能是一个 URL,这种情况下,会自动去下载这个链接的文件到 <目标路径>里,下载完成的文件权限自动设置为 600,如果不是想要的权限,那么可以通过 RUN 进行权限调整。

如果 <源路径> 为一个 tar 压缩文件的话,或者压缩格式为 gzip,bzip以及xz 的情况下,ADD 指令会自动解压缩这个压缩文件到 <目标路径>去。

示例

[root@docker01 /data/dockerfile/nginx]# vim dockerfile
FROM centos:7
RUN rm -rf /etc/yum.repos.d/* \
 && curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo \
 && curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo \
 && yum -y install nginx
WORKDIR /usr/share/nginx/html
RUN rm -rf ./*
ADD xiaoniao .
CMD ["nginx", "-g"," daemon off;"]
​
[root@docker01 /data/dockerfile/nginx]# docker build --network=host -t centos7_nginx:v6 .
​
[root@docker01 /data/dockerfile/nginx]# docker rm -f $(docker ps -qa )
564a5fb1fd91
cdea08555c04
[root@docker01 /data/dockerfile/nginx]# docker run -d -p 80:80 centos7_nginx:v6

访问测试

file5.png
[root@docker01 /data/dockerfile/nginx]# vim dockerfile
FROM centos:7
RUN rm -rf /etc/yum.repos.d/* \
 && curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo \
 && curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo \
 && yum -y install nginx
WORKDIR /usr/share/nginx/html
RUN rm -rf ./*
ADD xiaoniao.tar.gz .
CMD ["nginx", "-g"," daemon off;"]
​
[root@docker01 /data/dockerfile/nginx]# docker build --network=host -t centos7_nginx:v7 .
​
[root@docker01 /data/dockerfile/nginx]# docker rm -f $(docker ps -qa )
09273df6a44b
[root@docker01 /data/dockerfile/nginx]# docker run -d -p 80:80 centos7_nginx:v7
327c84ad622ff1809c586c83c4a28d3562b4638c0d7ebf31c62d88b1cbf3234e

测试访问

VOLUME 定义匿名卷

格式:

  • VOLUME ["<路径1>","<路径2>"...]

  • VOLUME <路径>

容器运行时应该尽量保持容器存储层不会发生写操作,对于数据库类需要保存动态数据的应用,其数据文件应该保存在数据卷中,为了防止运行时忘记将动态文件所保存目录挂载为卷,在Dockerfile中,可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会向容器存储层写入大量数据。

持久化

数据卷(文件或目录)

-v卷名:/data/(第一次卷是空,会将容器中的数据复制到卷中,如果卷里有数据,把卷数据挂载发到容器中)

-v src(宿主机目录):dest(容器的目录)

数据卷容器

--volumes-from (跟某一个已经存在的容器挂载相同的卷)

[root@docker01 /data/dockerfile/nginx]# vim dockerfile 
FROM centos:7
RUN rm -rf /etc/yum.repos.d/* \
 && curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo \
 && curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo \
 && yum -y install nginx
WORKDIR /usr/share/nginx/html
RUN rm -rf ./*
ADD xiaoniao .
VOLUME /usr/share/nginx/html
CMD ["nginx", "-g"," daemon off;"]
​
[root@docker01 ~]# docker run -d -p 80:80 centos_nginx:v8
85a83e7686bbbe832b56a1287cb25ee93c81d2bf1f382cff46bd8f0971adc2f9
[root@docker01 ~]# docker inspect 85a83e7686bbbe|grep volume
 "Type": "volume",
 "Source": "/var/lib/docker/volumes/d3a703e7685bba38585127494e04e2c77cc6c9923d14a8ea719862b506348448/_data",
[root@docker01 ~]# cd /var/lib/docker
docker/        docker-engine/ 
[root@docker01 ~]# cd /var/lib/docker/volumes/d3a703e7685bba38585127494e04e2c77cc6c9923d14a8ea719862b506348448/_data/
[root@docker01 /var/lib/docker/volumes/d3a703e7685bba38585127494e04e2c77cc6c9923d14a8ea719862b506348448/_data]# ls
2000.png  21.js  icon.png  img  index.html  sound1.mp3

测试访问

file7.png

重新开启一个新的容器,然后修改默认首页

[root@docker01 ~]# docker run -d --name xiaoniao -p 81:80 centos_nginx:v8

测试访问

数据卷容器

--volumes-from (跟某一个已经存在的容器挂载相同的卷)

从新启动一个容器与之前的容器挂载相同的卷

[root@docker01 ~]# docker run -d -p 82:80 --volumes-from xiaoniao centos_nginx:v8
13197ed39494ac33460bb2d71f9276c031a747dcd2ec53fdf11cae9ba722d232
​
[root@docker01 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
13197ed39494        centos_nginx:v8     "nginx -g ' daemon o…"   2 minutes ago       Up 2 minutes        0.0.0.0:82->80/tcp   gifted_lamarr
20aa69a9e60d        centos_nginx:v8     "nginx -g ' daemon o…"   12 minutes ago      Up 12 minutes       0.0.0.0:81->80/tcp   xiaoniao
85a83e7686bb        centos_nginx:v8     "nginx -g ' daemon o…"   17 minutes ago      Up 17 minutes       0.0.0.0:80->80/tcp   elated_keller

测试访问

EXPOSE 声明端口

格式:

  • EXPOSE <端口1> [<端口2>...]

EXPOSE 指令是声明运行容器时提供的服务端口,这只是一个声明,在运行时并不会因为这个声明就会开启这个端口的服务。在Dockerfile中写入这样的声明有两个好处,一个是帮助使用镜像者理解这个镜像服务的守护端口,以方便配置映射;另一个用处则是在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射EXPOSE的端口。

[root@docker01 /data/dockerfile/nginx]# vim dockerfile
FROM centos:7
RUN rm -rf /etc/yum.repos.d/* \
 && curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo \
 && curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo \
 && yum -y install nginx
WORKDIR /usr/share/nginx/html
RUN rm -rf ./*
ADD xiaoniao .
EXPOSE 80 22
CMD ["nginx", "-g"," daemon off;"]
​
[root@docker01 /data/dockerfile/nginx]# docker build -t centos_nginx:v9 .
​
[root@docker01 /data/dockerfile/nginx]# docker run -d -P centos_nginx:v9
b0f5378bf1ff847ea896dcadcae341e0db225ee623229e4c30b73d8c296f8f67
​
[root@docker01 /data/dockerfile/nginx]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                          NAMES
b0f5378bf1ff        centos_nginx:v9     "nginx -g ' daemon o…"   11 seconds ago      Up 10 seconds       0.0.0.0:32769->22/tcp, 0.0.0.0:32768->80/tcp   busy_joliot

CMD 容器启动命令

容器不是虚拟机,容器就是进程,既然是进程,那么在启动容器的时候,需要指定所运行的程序及参数。CMD 指令就是用于指定容器默认的主进程启动命令的。(容易被改变)

CMD 指令有三种格式:

  • shell 格式: CMD <命令>

  • exec 格式:CMD ["可执行文件","参数1","参数2", ...]

  • 参数列表格式:CMD ["参数1","参数2",...] , 这个时候CMD作为 ENTRYPOINT的参数。

在指令格式上,一般推荐使用exec 格式,这类格式在解析时会被解析为JSON数组,因此一定要使用双引号 “” ,而不要使用单引号。

如果使用shell 格式的话,实际的命令会被包装为 sh -c 的参数的形式进行执行。比如:

CMD echo $HOME</pre>

在实际执行中,会将其变更为:

CMD ["sh", "-c", "echo $HOME"]

在运行时可以指定新的命令来替代镜像设置中的这个默认命令,比如,centos镜像默认的 CMD 是 /bin/bash, 如果我们直接 docker run -it centos 的时候,会直接进入 bash。我们也可以在运行时指定别的命令,如 docker run -it centos cat /etc/passwd 。这就是用 cat /etc/passwd命令替换了默认的 /bin/bash 命令了。

前台执行和后台执行的问题:
 Docker 不是虚拟机,容器中的应用都应该以前台执行,而不是像虚拟机、物理机里面那样,用 start / systemctl 去启动后台服务,容器内没有后台服务的概念。
比如:如果我们将CMD 写成这样:
CMD service nginx start
然后会发现容器执行后就立刻退出了,甚至在容器内使用systemctl 命令结果却发现根本执行不了。这就是因为没有搞明白前台、后台的概念,没有区分容器和虚拟机的差异,依旧在以传统虚拟机的角度去理解容器
对于容器而言,其启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出,其它辅助进程不是它需要关心的东西。
而使用 service nginx start 命令,则是希望 start来已后台守护进程形式启动nginx服务。而 CMD service nginx start 会被理解为 CMD ["sh", "-c", "service nginx start"],因此主进程实际上是sh, 那么当service nginx start 命令结束后,sh 也就结束了, sh 作为主进程退出了,自然就会令容器退出。
正确的做法是直接执行 nginx 可执行文件,并且要求以前台形式。如:
CMD ["nginx", "-g"," daemon off;"]

ENTRYPOINT 入口点

ENTRYPOINT 的格式和 RUN 指令格式一样,分为 exec 格式 和shell格式。

ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数。ENTRYPOINT 在运行时也可以替代,不过比CMD要繁琐,需要通过 docker run 的参数 --entrypoint 来指定。

当指定了 ENTRYPOINT 后,CMD 的含义就发生了改变,不再是直接运行其命令,而是将 CMD 的内容作为参数传给 ENTRYPOINT 指令,换句话说实际执行时,将变为:

ENTRYPOINT "<CMD>"

那么问题来了? 有了CMD ,为什么还要有ENTRYPOINT呢? 这种 ENTRYPOINT "<CMD>" 有什么好处呢?

场景一:让镜像变成命令一样使用

假设我们需要一个得知自己当前公网IP的镜像,那么可以使用CMD来实现:

[root@docker01 /data/dockerfile/nginx]# vim dockerfile
FROM centos:7
CMD ["curl","-s","https://ip.cn"]                                                                        
[root@docker01 /data/dockerfile/nginx]# docker build -t centos:vi .
Sending build context to Docker daemon  267.8kB
Step 1/2 : FROM centos:7
 ---> 5e35e350aded
Step 2/2 : CMD ["curl","-s","https://ip.cn"]
 ---> Running in 1cd0d54ea938
Removing intermediate container 1cd0d54ea938
 ---> 5dfbd8f7e484
Successfully built 5dfbd8f7e484
Successfully tagged centos:vi
​
[root@docker01 /data/dockerfile/nginx]# docker run centos:vi
​
{"ip": "101.81.163.198", "country": "上海市", "city": "电信"}

这样看起来是可以当做命令来使用,不过命令一般有参数,CMD 中实质的命令是 curl, 如果希望显示HTTP头信息,就需要加上 -i 参数。

[root@docker01 /data/dockerfile/nginx]# docker run centos:vi -i
docker: Error response from daemon: OCI runtime create failed: container_linux.go:345: starting container process caused "exec: \"-i\": executable file not found in $PATH": unknown.

这里可以看到可执行文件找不到的报错, executable file not found。上面说过,跟在镜像名后面的是 command, 运行时会替换 CMD 的默认值,因此这里的 -i 替换了原来的 CMD,而不是添加在原来的 curl -s https://ip.cn 后面,而 -i 根本不是命令,所以找不到。

那么如果我们希望加入 -i 参数,我们就必须重新完整的输入这个命令:

[root@docker01 /data/dockerfile/nginx]# docker run centos:vi curl -i https://ip.cn #替换了默认的CMD
 % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
 Dload  Upload   Total   Spent    Left  Speed
100    67    0    67    0     0     16      0 --:--:--  0:00:03 --:--:--    16
HTTP/1.1 200 OK
Date: Thu, 09 Jan 2020 12:26:29 GMT
Content-Type: application/json; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: __cfduid=d0419e04a3638ee1d3087c5cf80f494101578572789; expires=Sat, 08-Feb-20 12:26:29 GMT; path=/; domain=.ip.cn; HttpOnly; SameSite=Lax
CF-Cache-Status: DYNAMIC
Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
Server: cloudflare
CF-RAY: 5526665d7be1e4cc-LAX
​
{"ip": "101.81.163.198", "country": "上海市", "city": "电信"}

显然这不是好的解决办法,而是用 ENTRYPOINT 就可以解决这个问题:

[root@docker01 /data/dockerfile/nginx]# vim dockerfile
FROM centos:7
ENTRYPOINT ["curl","-s","https://ip.cn"]
​
[root@docker01 /data/dockerfile/nginx]# docker build -t centos:v1 .
Sending build context to Docker daemon  267.8kB
Step 1/2 : FROM centos:7
 ---> 5e35e350aded
Step 2/2 : ENTRYPOINT ["curl","-s","https://ip.cn"]
 ---> Running in f992ba880014
Removing intermediate container f992ba880014
 ---> 8b36c3256b89
Successfully built 8b36c3256b89
Successfully tagged centos:v1
[root@docker01 /data/dockerfile/nginx]# docker run centos:v1
{"ip": "101.81.163.198", "country": "上海市", "city": "电信"}
[root@docker01 /data/dockerfile/nginx]# docker run centos:v1 -i
HTTP/1.1 200 OK
Date: Thu, 09 Jan 2020 12:32:11 GMT
Content-Type: application/json; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: __cfduid=d3c35693353a4686d5d6eebe258bb5d5c1578573131; expires=Sat, 08-Feb-20 12:32:11 GMT; path=/; domain=.ip.cn; HttpOnly; SameSite=Lax
CF-Cache-Status: DYNAMIC
Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
Server: cloudflare
CF-RAY: 55266eb75f10e4d0-LAX
​
{"ip": "101.81.163.198", "country": "上海市", "city": "电信"}

从上面可以看出,不加-i 参数可以运行成功, 加上-i参数也可以运行成功,且达到了curl -i 的效果。这是因为当存在 ENTRYPOINT 后,CMD 的内容将会作为参数传递给 ENTRYPOINT ,而这里 -i 就是新的CMD,因此会作为参数传递给curl,从而达到了我们预期的效果。

场景二:应用运行前的准备工作

启动容器就是启动主进程,但有些时候,启动主进程前,需要一些准备工作。比如 mysql 类的数据库,可能需要一些数据库配置、初始化的工作,这些工作要在最终的mysql 服务器运行之前解决。此外,可能希望避免使用root 用户去启动服务器, 从而提高安全性,而在启动还需要以 root 身份执行一些必要的准备工作,最后切换到服务用户启动服务等。或者除了服务外,其它命令依旧可以使用 root 身份执行,方便调试等。

这些准备工作是和容器 CMD 无关的,无论CMD 是什么,都需要事先进行一个预处理的工作。这种情况下,可以写一个脚本,然后放入 ENTRYPOINT 中去执行,而这个脚本会接到的参数 (也就是CMD)作为指令,在脚本最后执行。比如官方的redis 中就是这样做的:

FROM alpine:3.4 
...
RUN addgroup -S redis && adduser -S -G redis redis 
...
ENTRYPOINT ["docker-entrypoint.sh"]
EXPOSE 6379 
CMD ["redis-server"]

可以看到其中为了 redis 服务创建了redis 用户,并在最后指定了 ENTRYPOINT 为 docker-entrypoint.sh 脚本。

#!/bin/bash
...
# allow the container to be started with `--user` 
if [ "$1" = 'redis-server' -a "$(id -u)" = '0' ]; then
 chown -R redis .
 exec su-exec redis "$0" "$@"
fi
​
exec "$@"

该脚本的内容就是根据 CMD 的内容来判断,如果是 redis-server 的话,则切换到 redis用户身份启动服务,否则依旧使用 root 身份执行。比如:

# docker run -it redis id
uid=0(root) gid=0(root) groups=0(root)

示例1

[root@docker01 /data/dockerfile/nginx]# vim dockerfile
FROM centos:7
RUN rm -rf /etc/yum.repos.d/* \
 && curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo \
 && curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo \
 && yum -y install nginx
WORKDIR /usr/share/nginx/html
RUN rm -rf ./*
ADD xiaoniao .
ENTRYPOINT ["nginx"]
CMD ["-g", "daemon off;"]
​
[root@docker01 /data/dockerfile/nginx]# docker build -t centos_nginx:v10 .
​
[root@docker01 /data/dockerfile/nginx]# docker run -d -p 80:80 centos_nginx:v10
ff772730832e18068e01da1d1ce654314f222dc33e4628b8db8cc5b6f3703176
​
[root@docker01 /data/dockerfile/nginx]# docker run -d -p 81:80 centos_nginx:v10 sdhdhj
6f7772a652a5759aff7ab635453b300a775b7a1d91a30a08a5c55999c2987799
​
[root@docker01 /data/dockerfile/nginx]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
ff772730832e        centos_nginx:v10    "nginx -g 'daemon of…"   32 seconds ago      Up 31 seconds       0.0.0.0:80->80/tcp   strange_pare
​
[root@docker01 /data/dockerfile/nginx]# docker ps -a
CONTAINER ID        IMAGE                       COMMAND                  CREATED              STATUS                          PORTS                NAMES
6f7772a652a5        centos_nginx:v10            "nginx sdhdhj"           20 seconds ago       Exited (1) 20 seconds ago                            tender_rubin
ff772730832e        centos_nginx:v10            "nginx -g 'daemon of…"   37 seconds ago       Up 37 seconds                   0.0.0.0:80->80/tcp   strange_pare

示例2

[root@docker01 /data/dockerfile/nginx]# vim dockerfile
FROM centos:7
RUN rm -rf /etc/yum.repos.d/* \
 && curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo \
 && curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo \
 && yum -y install nginx
WORKDIR /usr/share/nginx/html
RUN rm -rf ./*
ADD xiaoniao .
ADD init.sh /init.sh
ENTRYPOINT ["/bin/bash","/init.sh"]
​
[root@docker01 /data/dockerfile/nginx]# docker build -t centos_nginx:v11 .
​
[root@docker01 /data/dockerfile/nginx]# docker run -d -p 80:80 centos_nginx:v11
eeac9eef5c6941bbd9581d4304d8f7f48ad89a39aecfd2e6479c50f9d424a144
​
[root@docker01 /data/dockerfile/nginx]# docker run -d -p 81:80 centos_nginx:v11 1111 #参数被当成参数,该脚本没有参数,所以可以正常启动
fb656151c391b84411cb8bfb6e2b8e5b6b321dc9ca1246f2b00026e13c01ed89
​
[root@docker01 /data/dockerfile/nginx]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
fb656151c391        centos_nginx:v11    "/bin/bash /init.sh …"   10 seconds ago      Up 10 seconds       0.0.0.0:81->80/tcp   lucid_wilson
eeac9eef5c69        centos_nginx:v11    "/bin/bash /init.sh"     29 seconds ago      Up 28 seconds       0.0.0.0:80->80/tcp   affectionate_pike
​
[root@docker01 /data/dockerfile/nginx]# docker ps -a
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS                      PORTS                NAMES
fb656151c391        centos_nginx:v11            "/bin/bash /init.sh …"   30 seconds ago      Up 29 seconds               0.0.0.0:81->80/tcp   lucid_wilson
eeac9eef5c69        centos_nginx:v11            "/bin/bash /init.sh"     49 seconds ago      Up 48 seconds               0.0.0.0:80->80/tcp   affectionate_pike

ENV 设置环境变量

格式:

  • ENV <key><value>

  • ENV<key1>=<value1> <key2>=<value2>

这个指令很简单,就是设置环境变量,无论是后面的其它指令,如RUN,还是运行时的应用,都可以直接使用这里定义的环境变量。

[root@docker01 /data/dockerfile/nginx]#  Dockerfile   #查看编辑好的Dockerfile文件内容
FROM centos
ENV name1 xiaobai
ENV name2=zhazha name3=cainiao
[root@docker01 /data/dockerfile/nginx]#  build -t mycentos:v5 .  #构建镜像
[root@docker01 /data/dockerfile/nginx]#  run --rm -it --name test mycentos:v5  #启动一个容器,并以交互式启动 
[root@b55929b2c63f /]# echo $name1  #进入容器后调用环境变量name1
xiaobai
[root@b55929b2c63f /]# echo $name2 $name3  #调用环境变量name2,name3
zhazha cainiao

定义了环境变量,可以在后续的指令中直接使用环境变量

FROM centos
ENV URL="https://nginx.org/download/" 
ADD $URLnginx.1.17.7.tar.gz /usr/local/

示例

[root@docker01 /data/dockerfile/nginx]# vim dockerfile
FROM centos:7
ADD http://nginx.org/download/nginx-1.17.7.tar.gz /opt/
RUN tar -xvzf /opt/nginx-1.17.7.tar.gz -C /usr/local/src/ \
 && useradd -M -s /sbin/nologin nginx
WORKDIR /usr/local/src/nginx-1.17.7
RUN ./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --with-file-aio --with-http_ssl_module --wi
th-http_realip_module --with-http_addition_module --with-http_xslt_module --with-http_image_filter_module --with
-http_geoip_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module -
-with-http_gunzip_module --with-http_gzip_static_module --with-http_auth_request_module --with-http_random_index
_module --with-http_secure_link_module --with-http_degradation_module --with-http_stub_status_module && make &&
make install
VOLUME ["/usr/local/nginx/html"]
RUN rm -rf /opt/nginx-1.17.7.tar.gz
ENV PATH=/usr/local/nginx/sbin:$PATH
EXPOSE 80
ENTRYPOINT ["nginx"]
CMD ["-g", "daemon off;"]
​
[root@docker01 /data/dockerfile/nginx]# docker build --network=host -t centos_nginxsrc:v4 .
​
[root@docker01 /data/dockerfile/nginx]# docker run -d -P centos_nginxsrc:v4
​
root@docker01 /data/dockerfile/nginx]# docker ps
CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              PORTS                   NAMES
8544d8311d16        centos_nginxsrc:v4   "nginx -g 'daemon of…"   4 minutes ago       Up 4 minutes        0.0.0.0:32771->80/tcp   gallant_neumann

访问测试

file10.png

ARG 构建参数

格式:

  • ARG <参数名>[=<默认值>]

构建参数和 ENV的效果一样,都是设置环境变量。所不同的是,ARG 所设置的构建环境和环境变量,在将来容器运行时是不会存在这些环境变量的。但是不要因此就使用 ARG 保存密码之类的信息,因为 docker history 还是可以看到所有值的。

Dockerfile 中的ARG指令是定义参数名称,以及定义其默认值。该默认值可以在构建命令 docker build 中用 --build-arg <参数名>=<值> 来覆盖。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容