基于Dockerfile构建镜像
1. Dockerfile:source code for building Docker file
- Docker可以通过从Dockerfile文件中读取指令自动构建镜像
- Dockerfile是一个文本文档,它包含用户可以在命令行上调用的所有命令来组装映像
- 使用Docker build命令,用户可以通过逐条执行几条命令自动创建镜像
2. Dockerfile语法格式:
- 首行必须是以#开头的行
- 不区分大小写,但约定俗成的惯例都是使用全部大写。
- Docker按顺序在Dockerfile中运行指令
- 第一个指令必须是“FROM”,以便指定要从其中构建的基本映像
3. 环境变量(使用ENV语句声明)也可以在某些指令中使用,作为由Dockerfile解释的变量。
- 在Dockerfile中,环境变量可以是{variable_name}
- ${variable_name}语法还支持一些标准bash修饰符
- ${variable:-word}表示,如果设置了变量,那么结果将是该值。如果变量未设置,则结果为word。
- ${variable:+word}表示如果设置了变量,那么结果将是word,否则结果将是空字符串。
4. .dockerignore文件
- 在工作目录中若有子目录,而子目录中有些文件不想引用,就可以用.dockerignore来隐藏文件。
- .dockerignore文件内指明不引用的文件。
4. FROM
- 用来指定基础镜像,若指定的镜像不存在,会先到Docker Hub中下载
- 语法:
- FROM
[AS ] #[AS ]:别名
- FROM
[:] [AS ] #tag:标签
- FROM
[@] [AS ] #digest:哈希码
- FROM
5. docker build命令
- Build an image from a Dockerfile
- Options
- -t, –tag list Name and optionally a tag in the ‘name:tag’ format
- -m, –memory bytes Memory limit
- -c, –cpu-shares int CPU shares (relative weight)
6. LABEL
- 添加镜像文件的元数据,可出现多次,强烈建议只使用一条,因为一条指令会添加一个层,层数越多,运行效率越低。
- 语法格式:
- LABEL = = =… #可指定多个LABEL
- LABEL #只可指定一个LABEL,第一个空格后的内容都会被当作value
示例
只修改一个镜像的FROM、LABEL
- 创建工作目录image
[root@docker ~]# mkdir image
[root@docker ~]# cd image
复制代码
- 编辑Dockerfile文件,添加以下内容:
[root@docker image]# vim Dockerfile
#Test Image Build
FROM alpine
LABEL maintainer="lixinkuan <lixinkuan@163.com>"
复制代码
- 制作镜像:
[root@docker image]# docker build .
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM alpine
---> 3fd9065eaf02
Step 2/2 : LABEL maintainer="lixinkuan <lixinkuan@163.com>"
---> Running in e1ce9acfc453
Removing intermediate container e1ce9acfc453
---> 1deb17a1af32
Successfully built 1deb17a1af32
复制代码
- 查看:REPOSITORY和TAG都为空的即为新创建的镜像文件
[root@docker image]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> 1deb17a1af32 5 minutes ago 4.15MB
nginx latest cd5239a0906a 3 weeks ago 109MB
busybox latest 8c811b4aec35 5 weeks ago 1.15MB
httpd 2.4 fb2f3851a971 8 weeks ago 178MB
alpine latest 3fd9065eaf02 5 months ago 4.15MB
复制代码
- 创建docker镜像时,可使用-t后跟 ‘name:tag’ 指定TAG
- 也可用如下命令添加标签:
[root@docker image]# docker image tag 1deb17a1af32 alpine:lxk
[root@docker image]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
alpine lxk 1deb17a1af32 5 minutes ago 4.41MB
复制代码
7. COPY
- 用于从Docker宿主机复制文件至创建的新映像文件
- 语法:
- COPY …
- COPY [“”,… “”]
- :要复制的源文件或目录,支持使用通配符
- :目标路径,即正在创建的image的文件系统路径;建议为使用绝对路径,否则,COPY指定则以WORKDIR为其起始路径
- 注意:在路径中有空白字符时,通常使用第二种格式
- 文件复制准则:
- 必须是build上下文中的路径,不能是其父目录中的文件
- 如果是目录,则其内部文件或子目录会被递归复制,但目录自身不会被复制
- 如果指定了多个,或在中使用了通配符,则必须是一个目录,且必须以/结尾
- 如果事先不存在,它将会被自动创建,这包括其父目录路径
示例:复制单个文件
- 在image目录下为index.html添加内容:
[root@docker image]# echo '<h1>hello,docker!</h1>' > index.html
复制代码
- 编辑Dockerfile文件,添加语句:
[root@docker image]# vim Dockerfile
#Test Image Build
FROM alpine
LABEL maintainer="lixinkuan <lixinkuan@163.com>"
COPY index.html /var/www/html/
复制代码
- 用alpine启动一个容器,查看是否有/var/www/html目录
[root@docker image]# docker run -it --name a1 alpine
/ # ps aux
PID USER TIME COMMAND
1 root 0:00 /bin/sh
7 root 0:00 ps aux
/ # ls /var/www/html
ls: /var/www/html: No such file or directory
复制代码
- 制作镜像
[root@docker image]# docker build -t cpindex:latest .
Sending build context to Docker daemon 3.072kB
Step 1/3 : FROM alpine
---> 3fd9065eaf02
Step 2/3 : LABEL maintainer="lixinkuan <lixinkuan@163.com>"
---> Running in 9d96e0655a82
Removing intermediate container 9d96e0655a82
---> 56049399eb78
Step 3/3 : COPY index.html /var/www/html/
---> bace8e55c97b
Successfully built bace8e55c97b
Successfully tagged cpindex:latest
复制代码
- 查看制作的镜像:
[root@docker image]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
cpindex latest bace8e55c97b 52 seconds ago 4.15MB
复制代码
- 以制作的镜像启动一个容器,并查看文件是否存在
[root@docker image]# docker run --name copyfile -it --rm cpindex:latest
/ # ls /var/www/html
index.html
/ # cat /var/www/html/index.html
<h1>hello,docker!</h1>
复制代码
示例:复制目录下的多个文件至目录
- 复制一个目录至/root/image下
[root@docker image]# cp -r /etc/default/ ./
[root@docker image]# ls
default Dockerfile index.html
[root@docker image]# ls default/
grub kibana nss useradd
复制代码
- 修改Dockerfile文件为以下内容:
#Test Image Build
FROM alpine
LABEL maintainer="lixinkuan <lixinkuan@163.com>"
COPY default /tmp/
复制代码
- 制作镜像:
[root@docker image]# docker build -t cpdir:latest ./
Sending build context to Docker daemon 9.216kB
Step 1/3 : FROM alpine
---> 3fd9065eaf02
Step 2/3 : LABEL maintainer="lixinkuan <lixinkuan@163.com>"
---> Using cache
---> 56049399eb78
Step 3/3 : COPY default /tmp/
---> 18cacf50aef9
Successfully built 18cacf50aef9
Successfully tagged cpdir:latest
复制代码
- 查看并验证:
[root@docker image]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
cpdir latest 18cacf50aef9 24 seconds ago 4.15MB
[root@docker image]# docker run --name cpdir -it --rm cpdir:latest
WARNING: IPv4 forwarding is disabled. Networking will not work.
/ # ls /tmp
grub kibana nss useradd
复制代码
示例:使用数组格式创建配置文件
- 修改配置文件如下:
#Test Image Build
FROM alpine
LABEL maintainer="lixinkuan <lixinkuan@163.com>"
COPY ["default","/tmp/default"]
复制代码
- 创建镜像并验证
[root@docker image]# docker build -t cp:latest ./
Sending build context to Docker daemon 9.216kB
Step 1/3 : FROM alpine
---> 3fd9065eaf02
Step 2/3 : LABEL maintainer="lixinkuan <lixinkuan@163.com>"
---> Using cache
---> 56049399eb78
Step 3/3 : COPY ["default","/tmp/default"]
---> bf0799319943
Successfully built bf0799319943
Successfully tagged cp:latest
[root@docker image]# docker run --name cp -it --rm cp:latest
/ # cd /tmp
/tmp # ls
default
/tmp # cd default/
/tmp/default # ls
grub kibana nss useradd
/tmp/default # exit
复制代码
8. ADD
- ADD类似于COPY指令,ADD支持tar文件和URL路径
- Syntax
- ADD …
- ADD [“”…””]
- 操作准则:
- 同COPY指令
- 如果为URL且不以/结尾,则指定的文件将被下载并直接被创建为;如果以/结尾,则文件名URL指定的文件将被直接下载并保存为/
- 如果是一个本地系统上的压缩格式的tar文件,它将被展开为一个目录,其行为类似于“tar -x”命令;然而,通过URL获取到的tar文件将不会自动展开;
- 如果有多个,或其间接或直接使用了通配符,则必须是一个以/结尾的目录路径;如果不以/结尾,则其被视作一个普通文件,的内容将被直接写入到
示例:下载一个文件至镜像文件
- 在工作目录下编写Dockerfile文件(使用URL时,用ftp协议失败)
#Test Image Build
FROM alpine
LABEL maintainer="lixinkuan <lixinkuan@163.com>"
COPY ["default","/tmp/default"]
ADD https://mirrors.aliyun.com/centos/7.5.1804/os/x86_64/Packages/zsh-5.0.2-28.el7.x86_64.rpm /tmp/
复制代码
- 创建镜像文件
[root@docker image]# docker build -t zsh:latest ./
Sending build context to Docker daemon 9.216kB
Step 1/4 : FROM alpine
---> 3fd9065eaf02
Step 2/4 : LABEL maintainer="lixinkuan <lixinkuan@163.com>"
---> Using cache
---> 56049399eb78
Step 3/4 : COPY ["default","/tmp/default"]
---> Using cache
---> bf0799319943
Step 4/4 : ADD https://mirrors.aliyun.com/centos/7.5.1804/os/x86_64/Packages/zsh-5.0.2-28.el7.x86_64.rpm /tmp/
Downloading [==================================================>] 2.494MB/2.494MB
---> 538ab9c6983e
Successfully built 538ab9c6983e
Successfully tagged zsh:latest
复制代码
- 创建容器并查看
[root@docker image]# docker run -it --name zsh --rm zsh:latest
/ # cd /tmp
/tmp # ls
default zsh-5.0.2-28.el7.x86_64.rpm
复制代码
示例:ADD一个压缩包至镜像文件
- 复制压缩包至工作目录,并在工作目录编辑Dockerfile文件
[root@docker image]# cp /root/wordpress-4.8.1-zh_CN.tar.gz ./
[root@docker image]# vim Dockerfile
#Test Image Build
FROM alpine
LABEL maintainer="lixinkuan <lixinkuan@163.com>"
ADD wordpress-4.8.1-zh_CN.tar.gz /tmp/
复制代码
- 制作镜像文件
[root@docker image]# docker build -t wordpress:latest ./
Sending build context to Docker daemon 8.652MB
Step 1/3 : FROM alpine
---> 3fd9065eaf02
Step 2/3 : LABEL maintainer="lixinkuan <lixinkuan@163.com>"
---> Using cache
---> 56049399eb78
Step 3/3 : ADD wordpress-4.8.1-zh_CN.tar.gz /tmp/
---> 58c32caba31e
Successfully built 58c32caba31e
Successfully tagged wordpress:latest
复制代码
- 创建容器并查看
[root@docker image]# docker run --name a1 -it --rm wordpress:latest
/ # ls /tmp/wordpress/
index.php wp-admin wp-content wp-load.php wp-signup.php
license.txt wp-blog-header.php wp-cron.php wp-login.php wp-trackback.php
readme.html wp-comments-post.php wp-includes wp-mail.php xmlrpc.php
wp-activate.php wp-config-sample.php wp-links-opml.php wp-settings.php
/ # exit
复制代码
9. WORKDIR
- 用于为Dockerfile中所有的RUN、CMD、ENTRYPOINT、COPY和ADD指定设定工作目录
- Syntax
- WORKDIR
- 在Dockerfile文件中,WORKDIR指令可出现多次,其路径也可以为相对路径,不过,其是相对此前一个WORKDIR指令指定的路径
- 另外,WORKDIR也可调用由ENV指定定义的变量
- 例如:
- WORKDIR /var/log
- WORKDIR $STATEPATH
- WORKDIR
示例
- 在工作目录下编辑Dockerfile文件:
#Test Image Build
FROM alpine
LABEL maintainer="lixinkuan <lixinkuan@163.com>"
WORKDIR /tmp
ADD wordpress-4.8.1-zh_CN.tar.gz src
复制代码
- 创建镜像:
[root@docker image]# docker build -t wordpress:v0.1 ./
Sending build context to Docker daemon 8.652MB
Step 1/4 : FROM alpine
---> 3fd9065eaf02
Step 2/4 : LABEL maintainer="lixinkuan <lixinkuan@163.com>"
---> Using cache
---> 56049399eb78
Step 3/4 : WORKDIR /tmp
Removing intermediate container 08bef4630472
---> 54f97eda6b49
Step 4/4 : ADD wordpress-4.8.1-zh_CN.tar.gz src
---> 0811aff4fa7d
Successfully built 0811aff4fa7d
Successfully tagged wordpress:v0.1
复制代码
- 创建容器后,默认工作路径就是WORKDIR所指的目录/tmp
[root@docker image]# docker run --name a1 -it --rm wordpress:v0.1
/tmp # ls
src
/tmp # ls src/
wordpress
/tmp # ls src/wordpress/
index.php wp-admin wp-content wp-load.php wp-signup.php
license.txt wp-blog-header.php wp-cron.php wp-login.php wp-trackback.php
readme.html wp-comments-post.php wp-includes wp-mail.php xmlrpc.php
wp-activate.php wp-config-sample.php wp-links-opml.php wp-settings.php
/tmp # exit
复制代码
10. VOLUME
- 用于在image中创建一个挂载点目录,以挂载Docker host上的卷或其它容器上的卷
- Syntax
- VOLUME
- VOLUME [“”]
- 如果挂载点目录路径下此前有文件存在,docker run命令会把原文件隐藏.
- 如果此前挂载点不存在,docker 会自动创建该目录.
- 挂载点下文件变化都可以在宿主机查看
- 查看方法:
- docker volume ls #查看宿主机所有挂载的目录
- docker inspect -f {{.Mounts}} a1 #通过查看指定容器信息查看挂载点路径
- 查看方法:
示例
- 在需要挂载的目录下提供文件
[root@docker image]# echo "hello,test dockerfile" > /var/www/html/index.html
复制代码
- 在工作目录下编辑Dockerfile文件
#Test Image Build
FROM alpine
LABEL maintainer="lixinkuan <lixinkuan@163.com>"
#WORKDIR /tmp
#ADD wordpress-4.8.1-zh_CN.tar.gz src/
VOLUME /var/www/html
复制代码
- 创建镜像文件
[root@docker image]# docker build -t file:v0.1 ./
Sending build context to Docker daemon 8.651MB
Step 1/3 : FROM alpine
---> 3fd9065eaf02
Step 2/3 : LABEL maintainer="lixinkuan <lixinkuan@163.com>"
---> Using cache
---> 56049399eb78
Step 3/3 : VOLUME /var/www/html
---> [Warning] IPv4 forwarding is disabled. Networking will not work.
---> Running in da84d9f4ca1e
Removing intermediate container da84d9f4ca1e
---> b26c2d7ea64c
Successfully built b26c2d7ea64c
Successfully tagged file:v0.1
复制代码
- 创建容器:
[root@docker image]# docker run --name a1 -it --rm file
/ # cd /var/www/html/
/var/www/html # echo abc > index.html
/var/www/html # cat index.html
abc
复制代码
- 查看宿主机上的文件:
[root@docker ~]# docker volume ls #查看本机所有容器挂载的目录
DRIVER VOLUME NAME
local 6368d0a0b462f5329a4b3bdcb7030e0d6f724bf9f801386f87fdac7660cd1735
[root@docker ~]# docker inspect -f {{.Mounts}} a1 #查看a1容器的挂载文件路径
[{volume 6368d0a0b462f5329a4b3bdcb7030e0d6f724bf9f801386f87fdac7660cd1735 /var/lib/docker/volumes/6368d0a0b462f5329a4b3bdcb7030e0d6f724bf9f801386f87fdac7660cd1735/_data /var/www/html local true }]
[root@docker ~]# cd /var/lib/docker/volumes/6368d0a0b462f5329a4b3bdcb7030e0d6f724bf9f801386f87fdac7660cd1735/_data/
[root@docker _data]# ls
index.html
[root@docker _data]# cat index.html
abc #该内容与容器中index.html内容一样
复制代码
11. EXPOSE
- 用于为容器打开指定要监听的端口以实现与外部通信
- 实质是通过iptables添加DNAT规则,把外网主机访问宿主机的请求转发至指定容器.
- 需要宿主机开启核心转发功能.
- 可通过iptables -t nat -nvL查看添加的规则.
- 通过Dockerfile制作镜像时若不用EXPOSE指定要暴露的端口,可用以下两种方法暴露端口:
- 容器运行后,自行添加DNAT规则实现端口暴露.
- docker run时使用-p选项指定暴露的端口.
- docker run时使用-P选项暴露所有容器内监听的端口.
- docker run时,使用-p选项指定的优先级要高于Dockerfile制作镜像时指定要暴露的端口.
- Syntax
- EXPOSE [/] [[/] …]
- 用于指定传输层协议,可为tcp或udp二者之一,默认为TCP协议
- EXPOSE [/] [[/] …]
- EXPOSE指令可一次指定多个端口,例如
- EXPOSE 11211/udp 11211/tcp
不用EXPOSE时,宿主机内容器若要被外网主机访问的情况
- 下载redis:4-alpine
[root@docker ~]# docker pull redis:4-alpine
4-alpine: Pulling from library/redis
ff3a5c916c92: Pull complete
5fbab8756652: Pull complete
ff7d4663b06c: Pull complete
0b5cf71258c2: Pull complete
54bbb9bad8ba: Pull complete
8fe9a341d124: Pull complete
Digest: sha256:686ab026fae07b3b99a8e74210c361714a80311ecc55f23b349ae930ed2f5a95
Status: Downloaded newer image for redis:4-alpine
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
redis 4-alpine caaeda72bf8f 12 days ago 27.8MB
复制代码
- 运行redis镜像
[root@docker ~]# docker run --name db1 -d --rm -p 6379 redis:4-alpine
881d5648c7388449a39c67024206c5710b1538f4c941039fa3905bb601b09699
[root@docker ~]# docker exec -it db1 ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02
inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:648 (648.0 B) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
[root@docker ~]# docker exec -it db1 /bin/sh
/data # netstat -tnl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:6379 0.0.0.0:* LISTEN
tcp 0 0 :::6379 :::* LISTEN
/data #
复制代码
- 查看映射的端口
[root@docker ~]# docker container port db1
6379/tcp -> 0.0.0.0:32768
复制代码
- 外网主机访问本地宿主机容器
[root@node1 tmp]# redis-cli -h 192.168.1.106 -p 32768
192.168.1.106:32768> select 1
OK
192.168.1.106:32768[1]> set mykey hi
OK
192.168.1.106:32768[1]> keys *
1) "mykey"
192.168.1.106:32768[1]> exit
复制代码
- 查看本地容器内是否有数据
[root@docker ~]# docker exec -it db1 /bin/sh
/data # redis-cli
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> keys *
1) "mykey"
127.0.0.1:6379[1]> exit
/data # exit
复制代码
开启自动端口暴露
- 在工作目录下编写Dockerfile文件
#Test Image Build
FROM redis:4-alpine
LABEL maintainer="lixinkuan <lixinkuan@163.com>"
EXPOSE 6379/tcp 26379/tcp
复制代码
- 制作镜像文件
[root@docker images]# docker build -t expose_db:latest ./
Sending build context to Docker daemon 8.645MB
Step 1/3 : FROM redis:4-alpine
---> caaeda72bf8f
Step 2/3 : LABEL maintainer="lixinkuan <lixinkuan@163.com>"
---> Running in f43f9e43b27a
Removing intermediate container f43f9e43b27a
---> e98bb940a8a2
Step 3/3 : EXPOSE 6379/tcp 26379/tcp
---> Running in f53a9be4f661
Removing intermediate container f53a9be4f661
---> ea40417716a0
Successfully built ea40417716a0
Successfully tagged expose_db:latest
复制代码
- 运行并查看效果
[root@docker images]# docker run --name a1 -d --rm -P redis_expose:latest
ad1225390f8f246cc5bde693ea99b120ee3a2f474416603b0797cda94787cc03
[root@docker images]# docker container port a1
6379/tcp -> 0.0.0.0:32772
复制代码
- 换一台主机连接数据库查看
[root@node1 ~]# redis-cli -h 192.168.200.45 -p 32772
192.168.200.45:32772> select 1
OK
192.168.200.45:32772[1]> keys *
(empty list or set)
192.168.200.45:32772[1]> set test dockerfile
OK
192.168.200.45:32772[1]> keys *
1) "test"
192.168.200.45:32772[1]> get test
"dockerfile"
复制代码
- 在a1容器上查看:
[root@docker images]# docker exec -it a1 /bin/sh
/data # redis-cli
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> get test
"dockerfile"
复制代码
示例:验证Dockerfile与docker run时使用-p的优先级
- 编辑Dockerfile
[root@docker images]# cat Dockerfile
#Test Image Build
FROM redis:4-alpine
LABEL maintainer="lixinkuan <lixinkuan@163.com>"
EXPOSE 6379/tcp 80/tcp
复制代码
- 制作镜像:
[root@docker images]# docker build -t expose_port .
Sending build context to Docker daemon 8.645MB
Step 1/3 : FROM redis:4-alpine
---> caaeda72bf8f
Step 2/3 : LABEL maintainer="lixinkuan <lixinkuan@163.com>"
---> Using cache
---> 188775dd2e3e
Step 3/3 : EXPOSE 6379/tcp 80/tcp
---> Running in b0f5bfbaafae
Removing intermediate container b0f5bfbaafae
---> 165e707c2b23
Successfully built 165e707c2b23
Successfully tagged expose_port:latest
复制代码
- 运行容器时指定要暴露的端口:
[root@docker images]# docker run --name db1 -d --rm -p 25 expose_port
e00f3e304103954c00651d44b00ae9961608900e0d5688eee4c08f140340f480
[root@docker images]# docker container port db1
25/tcp -> 0.0.0.0:32779
复制代码
- 查看防火墙规则,只有暴露25端口的DNAT规则
[root@docker images]# iptables -t nat -nvL
Chain DOCKER (2 references)
pkts bytes target prot opt in out source destination
0 0 RETURN all -- docker0 * 0.0.0.0/0 0.0.0.0/0
0 0 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:32779 to:172.17.0.2:25
复制代码
12. ENV
- 用于为镜像定义所需的环境变量,并可被Dockerfile文件中位于其后的其它指令(如ENV、ADD、COPY等)所调用
- 调用格式为{variable_name}
- Syntax
- ENV
- ENV = …
- 第一种格式中,之后的所有内容均会被视作其的组成部分,因此,一次只能设置一个变量
- 第二种格式可用一次设置多个变量,每个变量为一个”=”的键值对,如果中包含空格,可以以反斜线()进行转义,也可通过对加引号进行标识;另外,反斜线也可用于续行
- 定义多个变量时,建议使用第二种方式,以便在同一层中完成所有功能
示例
- 编辑Dockerfile文件
FROM busybox
LABEL maintainer="lixinkuan <lixinkuan@163.com>"
ENV DOCROOT="/data/web/html/"
COPY index.html ${DOCROOT}
VOLUME ${DOCROOT}
复制代码
- 提供index及所需挂载目录:
[root@docker bbox]# mkdir -pv /data/web/html
mkdir: created directory ‘/data’
mkdir: created directory ‘/data/web’
mkdir: created directory ‘/data/web/html’
[root@docker bbox]# echo hello Docker > index.html
[root@docker bbox]# cat index.html
hello Docker
复制代码
- 制作镜像:
[root@docker bbox]# docker build -t bbox_file:latest ./
Sending build context to Docker daemon 3.072kB
Step 1/5 : FROM busybox
latest: Pulling from library/busybox
07a152489297: Pull complete
Digest: sha256:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47
Status: Downloaded newer image for busybox:latest
---> 8c811b4aec35
Step 2/5 : LABEL maintainer="lixinkuan <lixinkuan@163.com>"
---> Running in 87a1f2c22ad6
Removing intermediate container 87a1f2c22ad6
---> 56f723d6220c
Step 3/5 : ENV DOCROOT="/data/web/html/"
---> Running in 21fd1fcb0474
Removing intermediate container 21fd1fcb0474
---> c095f8dd8418
Step 4/5 : COPY index.html ${DOCROOT}
---> ee77cd16629a
Step 5/5 : VOLUME ${DOCROOT}
---> Running in 00474fde8b85
Removing intermediate container 00474fde8b85
---> d51ea735fdd3
Successfully built d51ea735fdd3
Successfully tagged bbox_file:latest
复制代码
- 运行容器并查看
[root@docker bbox]# docker run --name a1 -it --rm bbox_file:latest
/ # ls /data/web/html
index.html
/ # cat /data/web/html/index.html
hello Docker
复制代码
- 另启终端查看挂载的卷:
[root@docker ~]# docker volume ls
DRIVER VOLUME NAME
local 1dcd37d2c4f2e6a71e0b96a385714ff01cad5d578e396c9b012922e9993aecbf
local b2df5fcd0e1aa58c403d2e8f0ec880feb7dcb1a80a688697e76122adec55e789
[root@docker ~]# docker inspect -f {{.Mounts}} a1
[{volume 1dcd37d2c4f2e6a71e0b96a385714ff01cad5d578e396c9b012922e9993aecbf /var/lib/docker/volumes/1dcd37d2c4f2e6a71e0b96a385714ff01cad5d578e396c9b012922e9993aecbf/_data /data/web/html local true }]
复制代码
13. CMD与RUN
- CMD
- 用于定义镜像启动为容器时默认运行的应用程序。
- 类似于RUN指令,CMD指令也可用于运行任何命令或应用程序,不过,二者的运行时间点不同
- RUN指令运行于映像文件构建过程中,而CMD指令运行于基于Dockerfile构建出的新映像文件启动一个容器时
- CMD指令的首要目的在于为启动的容器指定默认要运行的程序,且其运行结束后,容器也将终止;不过,CMD指定的命令其可以被docker run的命令行选项所覆盖
- 在Dockerfile中可以存在多个CMD指令,但仅最后一个会生效
- Syntax
- CMD
- CMD [“”, “”, “”]
- CMD [“”,””]
- 前两种语法格式的意义同RUN
- 第三种则用于为ENTRYPOINT指令提供默认参数
- RUN
- 指定docker build过程中运行的程序。必须是镜像中存在的命令。
- Syntax
- RUN
- RUN [“”, “”, “”]
- 第一种格式中,通常是一个shell命令,且以“/bin/sh -c”来运行它,这意味着此进程在容器中的PID不为1,不能接收Unix信号,因此,当使用docker stop 命令停止容器时,此进程接收不到SIGTERM信号;
- 第二种语法格式中的参数是一个JSON格式的数组,其中为要运行的命令,后面的为传递给命令的选项或参数;然而,此种格式指定的命令不会以“/bin/sh -c”来发起,因此常见的shell操作如变量替换以及通配符(?,*等)替换将不会进行;不过,如果要运行的命令依赖于此shell特性的话,可以将其替换为类似下面的格式。
- 示例:RUN [“/bin/bash”, “-c”, “”, “”]
示例1:基于centos基础镜像创建一个运行nginx的镜像
- 编辑Dockerfile文件:
FROM centos
LABEL maintainer="lixinkuan <lixinkuan@163.com>"
COPY base.repo epel.repo /etc/yum.repos.d/
RUN yum -y install nginx \
&& yum clean all \
&& rm -rf /var/cache/yum
复制代码
- 提供base.repo epel.repo文件:
[root@docker nginx]# wget lixinkuan.top/base.repo
--2018-06-30 11:29:08-- http://lixinkuan.top/base.repo
Resolving lixinkuan.top (lixinkuan.top)... 47.94.102.99
Connecting to lixinkuan.top (lixinkuan.top)|47.94.102.99|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 630
Saving to: ‘base.repo’
100%[=================================================================================>] 630 --.-K/s in 0s
2018-06-30 11:29:08 (87.9 MB/s) - ‘base.repo’ saved [630/630]
[root@docker nginx]# wget lixinkuan.top/epel.repo
--2018-06-30 11:29:16-- http://lixinkuan.top/epel.repo
Resolving lixinkuan.top (lixinkuan.top)... 47.94.102.99
Connecting to lixinkuan.top (lixinkuan.top)|47.94.102.99|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 214
Saving to: ‘epel.repo’
100%[=================================================================================>] 214 --.-K/s in 0s
2018-06-30 11:29:16 (44.2 MB/s) - ‘epel.repo’ saved [214/214]
[root@docker nginx]# ls
base.repo Dockerfile epel.repo
复制代码
- 创建镜像:
[root@docker nginx]# docker build -t nginx:v0.1 ./
Sending build context to Docker daemon 4.608kB
Step 1/4 : FROM centos
latest: Pulling from library/centos
7dc0dca2b151: Pull complete
Digest: sha256:b67d21dfe609ddacf404589e04631d90a342921e81c40aeaf3391f6717fa5322
Status: Downloaded newer image for centos:latest
---> 49f7960eb7e4
Step 2/4 : LABEL maintainer="lixinkuan <lixinkuan@163.com>"
---> Running in 6b16128ed7ca
Removing intermediate container 6b16128ed7ca
---> b6ef19a3311f
Step 3/4 : COPY base.repo epel.repo /etc/yum.repos.d/
---> e571c2837442
Step 4/4 : RUN yum -y install nginx && yum clean all && rm -rf /var/cache/yum
---> Running in 445372de8e8d
Loaded plugins: fastestmirror, ovl
.....
执行安装过程省略
...
Cleaning repos: base epel extras updates
Cleaning up everything
Maybe you want: rm -rf /var/cache/yum, to also free up space taken by orphaned data from disabled or removed repos
Cleaning up list of fastest mirrors
Removing intermediate container 445372de8e8d
---> 5cf6e8e3517e
Successfully built 5cf6e8e3517e
Successfully tagged nginx:v0.1
复制代码
- 创建容器并查看:
[root@docker nginx]# docker run --name web -it nginx:v0.1
[root@5e7adf4282c1 /]# rpm -q nginx
nginx-1.12.2-2.el7.x86_64 #nginx已安装
[root@5e7adf4282c1 /]#
复制代码
示例2:以busybox制作一个挂载本地/data/web/html目录并自动运行httpd的镜像
- 在工作目录编辑Dockerfile文件
FROM busybox
LABEL maintainer="lixinkuan <lixinkuan@163.com>"
ENV DOCROOT="/data/web/html/"
COPY index.html ${DOCROOT}
VOLUME ${DOCROOT}
CMD /bin/httpd -f -h ${DOCROOT}
复制代码
- 提供index.html并创建要挂载的目录
[root@docker bbox]# echo hello Docker > index.html
[root@docker bbox]# cat index.html
hello Docker
复制代码
- 创建镜像文件:
[root@docker bbox]# docker build -t web:v0.1 ./
Sending build context to Docker daemon 3.072kB
Step 1/6 : FROM busybox
---> 8c811b4aec35
Step 2/6 : LABEL maintainer="lixinkuan <lixinkuan@163.com>"
---> Using cache
---> 56f723d6220c
Step 3/6 : ENV DOCROOT="/data/web/html/"
---> Using cache
---> c095f8dd8418
Step 4/6 : COPY index.html ${DOCROOT}
---> Using cache
---> ee77cd16629a
Step 5/6 : VOLUME ${DOCROOT}
---> Using cache
---> d51ea735fdd3
Step 6/6 : CMD /bin/httpd -f -h ${DOCROOT}
---> Running in f2fa2b284306
Removing intermediate container f2fa2b284306
---> b8613217ad3c
Successfully built b8613217ad3c
Successfully tagged web:v0.1
复制代码
- 以新创建的镜像文件运行容器并查看
[root@docker bbox]# docker run --name web -d --rm web:v0.1
7b71084ebd922728ebf21d22a4e5ff3462443761c82bc22c640764c6d4925b2a
[root@docker bbox]# docker container inspect -f {{.Config.Cmd}} web
[/bin/sh -c /bin/httpd -f -h ${DOCROOT}]
[root@docker bbox]# docker exec -it web /bin/sh
/ # ps aux
PID USER TIME COMMAND
1 root 0:00 /bin/httpd -f -h /data/web/html/
7 root 0:00 /bin/sh
13 root 0:00 ps aux
/ # netstat -tnl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 :::80 :::* LISTEN
复制代码
示例3:docker run 时不运行镜像默认进程,运行指定指令
- 查看当前镜像文件:
[root@docker bbox]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
web v0.1 b8613217ad3c 2 hours ago 1.15MB
复制代码
- 以web:v0.1创建容器,不运行默认命令
[root@docker bbox]# docker run --name web -it --rm web:v0.1 /bin/sh
/ # netstat -tnl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
/ # ps aux
PID USER TIME COMMAND
1 root 0:00 /bin/sh
7 root 0:00 ps aux
复制代码
14. ENTRYPOINT
- 类似CMD指令的功能,用于为容器指定默认运行程序,从而使得容器像是一个单独的可执行程序
- 与CMD不同的是,由ENTRYPOINT启动的程序不会被docker run命令行指定的参数所覆盖,而且,这些命令行参数会被当作参数传递给ENTRYPOINT指定指定的程序
- 不过,docker run命令的–entrypoint选项的参数可覆盖ENTRYPOINT指令指定的程序
- Syntax
- ENTRYPOINT
- ENTRYPOINT [“”, “”, “”]
- docker run命令传入的命令参数会覆盖CMD指令的内容并且附加到ENTRYPOINT命令最后做为其参数使用
- Dockerfile文件中也可以存在多个ENTRYPOINT指令,但仅有最后一个会生效
示例1:
- 编辑Dockerfile文件
FROM busybox
LABEL maintainer="lixinkuan <lixinkuan@163.com>"
VOLUME /data/web/html/
COPY index.html /data/web/html/
EXPOSE 80/tcp
ENTRYPOINT ["/bin/httpd","-f","-h","/data/web/html"]
复制代码
- 创建镜像
[root@docker bbox]# docker build -t web:v0.2 ./
Sending build context to Docker daemon 3.072kB
Step 1/6 : FROM busybox
---> 8c811b4aec35
Step 2/6 : LABEL maintainer="lixinkuan <lixinkuan@163.com>"
---> Using cache
---> 56f723d6220c
Step 3/6 : VOLUME /data/web/html/
---> Running in 3095065d0ebb
Removing intermediate container 3095065d0ebb
---> 36dc68fabc6f
Step 4/6 : COPY index.html /data/web/html/
---> e47f81ec7728
Step 5/6 : EXPOSE 80/tcp
---> Running in f86f957ec882
Removing intermediate container f86f957ec882
---> 01a005644fe6
Step 6/6 : ENTRYPOINT ["/bin/httpd","-f","-h","/data/web/html"]
---> Running in 7a5f8b4f4acf
Removing intermediate container 7a5f8b4f4acf
---> 43d514096d34
Successfully built 43d514096d34
Successfully tagged web:v0.2
复制代码
- 创建容器运行并查看:
[root@docker bbox]# docker exec -it web /bin/sh
/ # ps aux
PID USER TIME COMMAND
1 root 0:00 /bin/httpd -f -h /data/web/html
7 root 0:00 /bin/sh
13 root 0:00 ps aux
/ # netstat -tnl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 :::80 :::* LISTEN
/ #
复制代码
- 运行容器时指定执行/bin/sh
[root@docker bbox]# docker run --name web -it --rm web:v0.2 /bin/sh
复制代码
- 换另一tty查看
[root@docker bbox]# docker exec -it web /bin/sh
/ # ps aux
PID USER TIME COMMAND
1 root 0:00 /bin/httpd -f -h /data/web/html /bin/sh
7 root 0:00 /bin/sh
13 root 0:00 ps aux
复制代码
并未执行/bin/sh,而是执行默认程序,/bin/sh被当作参数传递给/bin/httpd
示例:在docker run时使用entrypoint的时候更换默认运行的程序
- –entrypoint string Overwrite the default ENTRYPOINT of the image
- 使用镜像web:v0.2创建容器运行时添加–entrypoint选项
[root@docker bbox]# docker run --name web -it --rm --entrypoint /bin/sh web:v0.2
/ # ps aux
PID USER TIME COMMAND
1 root 0:00 /bin/sh
7 root 0:00 ps aux
/ # netstat -tnl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
/ #
复制代码
示例
- 编辑Dockerfile文件
FROM busybox
LABEL maintainer="lixinkuan <lixinkuan@163.com>"
ENV DOCROOT="/data/web/html/" MYPORT="80"
COPY index.html ${DOCROOT}
COPY entrypoint.sh /bin/
COPY test.conf /etc/
VOLUME ${DOCROOT}
EXPOSE 80/tcp
#CMD /bin/httpd -f -h ${DOCROOT}
#CMD ["/bin/sh","-c","/bin/httpd","-f","-h","${DOCROOT}"]
ENTRYPOINT ["/bin/entrypoint.sh"]
CMD ["/bin/httpd","-f","-h","/data/web/html/"]
复制代码
- 提供必须文件(脚本文件需加执行权限)
[root@docker bbox]# cat entrypoint.sh
#!/bin/sh
sed -i "s@^PORT=.*@PORT=${MYPORT}@g" /etc/test.conf
exec "$@"
[root@docker bbox]# cat test.conf
PORT=8080
复制代码
- 制作镜像:
[root@docker bbox]# docker build -t web:v0.3 ./
Sending build context to Docker daemon 5.12kB
Step 1/10 : FROM busybox
---> 8c811b4aec35
Step 2/10 : LABEL maintainer="lixinkuan <lixinkuan@163.com>"
---> Using cache
---> 56f723d6220c
Step 3/10 : ENV DOCROOT="/data/web/html/" MYPORT="80"
---> Running in f237100ec645
Removing intermediate container f237100ec645
---> f754b5dcea84
Step 4/10 : COPY index.html ${DOCROOT}
---> 3c31424c9b3d
Step 5/10 : COPY entrypoint.sh /bin/
---> 46ec2f5ede8c
Step 6/10 : COPY test.conf /etc/
---> 7db53e00338a
Step 7/10 : VOLUME ${DOCROOT}
---> Running in 5ae02469f585
Removing intermediate container 5ae02469f585
---> 0e1e3e966318
Step 8/10 : EXPOSE 80/tcp
---> Running in ae76bcf870ca
Removing intermediate container ae76bcf870ca
---> dea89896460d
Step 9/10 : ENTRYPOINT ["/bin/entrypoint.sh"]
---> Running in 6862bf4a336e
Removing intermediate container 6862bf4a336e
---> ca568e1ff983
Step 10/10 : CMD ["/bin/httpd","-f","-h","/data/web/html/"]
---> Running in 2aa5dea11848
Removing intermediate container 2aa5dea11848
---> 26bb44795880
Successfully built 26bb44795880
Successfully tagged web:v0.3
复制代码
- 运行容器并查看配置文件是否被修改
[root@docker bbox]# docker run --name web -d --rm web:v0.3
6ec1f5a008e6a08047e8666f6ed3ad4673360805148789faf780baf335ee5637
[root@docker bbox]# docker exec -it web /bin/sh
/ # netstat -tnl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 :::80 :::* LISTEN
/ # cat /etc/test.conf
PORT=80
/ # exit
复制代码
示例:通过传递变量更改配置文件的方法:
[root@docker bbox]# docker run –name web1 -d –rm -e MYPORT=10080 web:v0.3
7e3b353e423839d598ee9423e881673066cf99626940b6590e78f34b7622834d
[root@docker bbox]# docker exec -it web1 /bin/sh
/ # cat /etc/test.conf
PORT=10080
/ #
### 15.
-
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END