概述
github项目地址:https://github.com/superwujc
尊重原创,欢迎转载,注明出处:https://my.oschina.net/superwjc/blog/3045629
历史系列:
docker CE on Linux示例浅析(一)安装与基本运行
docker CE on Linux示例浅析(二)数据存储与持久化
镜像是静态存储的磁盘文件,容器是动态运行的内存进程,二者可以视为docker一体的两面。在docker的整个工作流程中,与镜像与容器相关的操作贯穿始终,其他功能大都以此为基础进行展开或封装。本文将以jdk + tomcat为例,简述镜像/容器的基本管理,包括构建与运行,以及迁移与恢复过程。
环境
- 宿主机2台:dock_host_0(192.168.9.168/24),dock_host_1(192.168.9.169/24),均为全新最小化安装,二者的系统与软件环境一致。操作系统版本CentOS Linux release 7.6.1810 (Core),内核版本3.10.0-957.12.1.el7.x86_64,docker为默认安装,版本18.09.5,无其他设置。
- 源码包jdk-8u212-linux-x64.tar.gz与apache-tomcat-8.5.40.tar.gz,位于宿主机的/opt/目录。
- 容器所用镜像为最新版CentOS 7官方镜像。
- jdk环境以命名卷jdks的方式挂载至容器的/opt/jdks目录,以减小镜像占用的磁盘空间,并加快镜像构建的速度。
- tomcat环境位于容器的/opt/apps/app_0目录,所有设置均为默认。
示例
获取操作系统镜像centos,并设置命名卷jdks:
[root@docker_host_0 ~]# ip addr show eth0 | sed -n '/inet /p' | awk '{print $2}'
192.168.9.168/24
[root@docker_host_0 ~]# docker -v
Docker version 18.09.5, build e8ff056
[root@docker_host_0 ~]#
[root@docker_host_0 ~]# docker pull centos
Using default tag: latest
latest: Pulling from library/centos
8ba884070f61: Pull complete
Digest: sha256:8d487d68857f5bc9595793279b33d082b03713341ddec91054382641d14db861
Status: Downloaded newer image for centos:latest
[root@docker_host_0 ~]#
[root@docker_host_0 ~]# docker image ls -a
REPOSITORY TAG IMAGE ID CREATED SIZE
centos latest 9f38484d220f 7 weeks ago 202MB
[root@docker_host_0 ~]#
[root@docker_host_0 ~]# cd /opt/
[root@docker_host_0 opt]#
[root@docker_host_0 opt]# ll
total 199908
-rw-r--r-- 1 root root 9690027 May 5 21:55 apache-tomcat-8.5.40.tar.gz
drwx--x--x 4 root root 28 May 5 22:04 containerd
-rw-r--r-- 1 root root 195013152 May 5 21:55 jdk-8u212-linux-x64.tar.gz
[root@docker_host_0 opt]#
[root@docker_host_0 opt]# docker volume create jdks
jdks
[root@docker_host_0 opt]# docker volume ls
DRIVER VOLUME NAME
local jdks
[root@docker_host_0 opt]#
[root@docker_host_0 opt]# tar axf jdk-8u212-linux-x64.tar.gz -C /var/lib/docker/volumes/jdks/_data/
[root@docker_host_0 opt]# ll /var/lib/docker/volumes/jdks/_data/
total 0
drwxr-xr-x 7 10 143 245 Apr 2 04:49 jdk1.8.0_212
[root@docker_host_0 opt]#
[root@docker_host_1 ~]# ip addr show eth0 | sed -n '/inet /p' | awk '{print $2}'
192.168.9.169/24
[root@docker_host_1 ~]# docker -v
Docker version 18.09.5, build e8ff056
[root@docker_host_1 ~]#
[root@docker_host_1 ~]# docker pull centos
Using default tag: latest
latest: Pulling from library/centos
8ba884070f61: Pull complete
Digest: sha256:8d487d68857f5bc9595793279b33d082b03713341ddec91054382641d14db861
Status: Downloaded newer image for centos:latest
[root@docker_host_1 ~]#
[root@docker_host_1 ~]# docker image ls -a
REPOSITORY TAG IMAGE ID CREATED SIZE
centos latest 9f38484d220f 7 weeks ago 202MB
[root@docker_host_1 ~]#
[root@docker_host_1 ~]# cd /opt/
[root@docker_host_1 opt]# ll
total 199908
-rw-r--r-- 1 root root 9690027 May 5 21:55 apache-tomcat-8.5.40.tar.gz
drwx--x--x 4 root root 28 May 5 21:58 containerd
-rw-r--r-- 1 root root 195013152 May 5 21:55 jdk-8u212-linux-x64.tar.gz
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# docker volume create jdks
jdks
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# docker volume ls
DRIVER VOLUME NAME
local jdks
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# tar axf jdk-8u212-linux-x64.tar.gz -C /var/lib/docker/volumes/jdks/_data/
[root@docker_host_1 opt]# ll /var/lib/docker/volumes/jdks/_data/
total 0
drwxr-xr-x 7 10 143 245 Apr 2 04:49 jdk1.8.0_212
[root@docker_host_1 opt]#
3.1 构建
docker镜像的构建过程为逐层进行,上层镜像称为父(parent)镜像,顶层镜像称为基础(base)镜像,通常为操作系统。对于运行中的容器,其可写层中产生的内容变更经过保存(commit),与父镜像共同组成当前层级的镜像。
镜像的构建可以通过手动与自动的方式。手动方式为重复运行父镜像,将需要定制的内容逐步添加到可写层并保存;自动方式则将需要实现的功能写入到文件(Dockerfile),由docker主进程读取该文件,并按指令完成构建。
3.1.1 手动构建
以名称t_c_0运行centos镜像,并在容器中创建/opt/apps目录:
[root@docker_host_0 opt]# docker run --name t_c_0 centos bash -c "mkdir -p /opt/apps"
[root@docker_host_0 opt]#
[root@docker_host_0 opt]# docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6a6a3ed5a380 centos "bash -c 'mkdir -p /…" 8 seconds ago Exited (0) 7 seconds ago t_c_0
[root@docker_host_0 opt]#
将tomcat复制到容器的/opt/apps/app_0目录:
[root@docker_host_0 opt]# tar axf apache-tomcat-8.5.40.tar.gz
[root@docker_host_0 opt]#
[root@docker_host_0 opt]# ll -d apache-tomcat-8.5.40
drwxr-xr-x 9 root root 220 May 5 22:15 apache-tomcat-8.5.40
[root@docker_host_0 opt]#
[root@docker_host_0 opt]# docker cp apache-tomcat-8.5.40 t_c_0:/opt/apps/app_0
[root@docker_host_0 opt]#
将t_c_0容器的当前状态保存为t_i_0镜像:
[root@docker_host_0 opt]# docker container commit t_c_0 t_i_0
sha256:1aa86a5d25c2933cbf1b5e455435b44b3eb3c5501190116d02c6028cda11a318
[root@docker_host_0 opt]#
[root@docker_host_0 opt]# docker image ls -a
REPOSITORY TAG IMAGE ID CREATED SIZE
t_i_0 latest 1aa86a5d25c2 5 seconds ago 216MB
centos latest 9f38484d220f 7 weeks ago 202MB
[root@docker_host_0 opt]#
以名称t_c_1运行t_i_0镜像,并指定容器的开放端口(--expose),环境变量(-e/--env),工作目录(-w/--workdir):
[root@docker_host_0 opt]# docker run --name t_c_1 --expose 8080 --env JAVA_HOME=/opt/jdks/jdk1.8.0_212 --workdir /opt/apps/app_0 t_i_0 /bin/bash
[root@docker_host_0 opt]#
[root@docker_host_0 opt]# docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
63258c74cb4b t_i_0 "/bin/bash" 8 seconds ago Exited (0) 6 seconds ago t_c_1
6a6a3ed5a380 centos "bash -c 'mkdir -p /…" 3 minutes ago Exited (0) 3 minutes ago t_c_0
[root@docker_host_0 opt]#
将t_c_1容器的当前状态保存为t_i_1镜像:
[root@docker_host_0 opt]# docker container commit t_c_1 t_i_1
sha256:c5f0d673d958aad49db41e154bf723bb947be257a9999014881ab90e8f155106
[root@docker_host_0 opt]#
[root@docker_host_0 opt]# docker image ls -a
REPOSITORY TAG IMAGE ID CREATED SIZE
t_i_1 latest c5f0d673d958 7 seconds ago 216MB
t_i_0 latest 1aa86a5d25c2 2 minutes ago 216MB
centos latest 9f38484d220f 7 weeks ago 202MB
[root@docker_host_0 opt]#
以t_i_1为父镜像创建t_c_2容器,并添加命令"bin/startup.sh && tail -f logs/catalina.out":
docker create与docker run都可以为镜像添加命令,区别在于create命令仅添加而不运行,run命令则既添加且运行。本例中运行最终镜像需要挂载jdk环境,否则将报错而启动失败,且将不必要的日志文件编译进镜像中,因此使用create命令而非run命令。
[root@docker_host_0 opt]# docker container create --name t_c_2 t_i_1 bash -c "bin/startup.sh && tail -f logs/catalina.out"
e414c244d72525431607f4f439fe7590600316a97cda17f78d4ee8b1d0c25bf8
[root@docker_host_0 opt]#
[root@docker_host_0 opt]# docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e414c244d725 t_i_1 "bash -c 'bin/startu…" 6 seconds ago Created t_c_2
63258c74cb4b t_i_0 "/bin/bash" 2 minutes ago Exited (0) 2 minutes ago t_c_1
6a6a3ed5a380 centos "bash -c 'mkdir -p /…" 5 minutes ago Exited (0) 5 minutes ago t_c_0
[root@docker_host_0 opt]#
将t_c_2容器的当前状态保存为tomcat_app_manual镜像,手动构建完成。
[root@docker_host_0 opt]# docker container commit t_c_2 tomcat_app_manual
sha256:557c9112cb3f132de99f850bf11a5954a15816e30fa45fd2ab01f9c3030f02f1
[root@docker_host_0 opt]#
[root@docker_host_0 opt]# docker image ls -a
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat_app_manual latest 557c9112cb3f 8 seconds ago 216MB
t_i_1 latest c5f0d673d958 About a minute ago 216MB
t_i_0 latest 1aa86a5d25c2 3 minutes ago 216MB
centos latest 9f38484d220f 7 weeks ago 202MB
[root@docker_host_0 opt]#
查看镜像的属性信息:
inspect命令的--format选项用于以go模板格式化输出,也可以通过shell的grep/awk/sed手动过滤,以查看指定块与字段。
[root@docker_host_0 opt]# docker image inspect --format='{{ .Config.Env }}' tomcat_app_manual
[JAVA_HOME=/opt/jdks/jdk1.8.0_212 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin]
[root@docker_host_0 opt]# docker image inspect --format='{{ .Config.ExposedPorts }}' tomcat_app_manual
map[8080/tcp:{}]
[root@docker_host_0 opt]# docker image inspect --format='{{ .Config.WorkingDir }}' tomcat_app_manual
/opt/apps/app_0
[root@docker_host_0 opt]# docker image inspect --format='{{ .Config.Cmd }}' tomcat_app_manual
[bash -c bin/startup.sh && tail -f logs/catalina.out]
[root@docker_host_0 opt]#
以名称app_man运行tomcat_app_manual镜像,挂载共享卷并映射端口:
[root@docker_host_0 opt]# docker run -dit --name app_man -p 8080:8080 --mount src=jdks,dst=/opt/jdks,ro tomcat_app_manual
a5c1750f880c3873d14d48dd237f9e47eaa08184117fe4c79e53e001997dcd2e
[root@docker_host_0 opt]#
[root@docker_host_0 opt]# docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a5c1750f880c tomcat_app_manual "bash -c 'bin/startu…" 5 seconds ago Up 5 seconds 0.0.0.0:8080->8080/tcp app_man
e414c244d725 t_i_1 "bash -c 'bin/startu…" 6 minutes ago Created t_c_2
63258c74cb4b t_i_0 "/bin/bash" 8 minutes ago Exited (0) 8 minutes ago t_c_1
6a6a3ed5a380 centos "bash -c 'mkdir -p /…" 11 minutes ago Exited (0) 11 minutes ago t_c_0
[root@docker_host_0 opt]#
容器内的tomcat进程成功启动,并已创建端口映射:
[root@docker_host_0 opt]# docker container top app_man
UID PID PPID C STIME TTY TIME CMD
root 7769 7751 0 22:25 pts/0 00:00:00 bash -c bin/startup.sh && tail -f logs/catalina.out
root 7815 7769 1 22:25 pts/0 00:00:02 /opt/jdks/jdk1.8.0_212/bin/java -Djava.util.logging.config.file=/opt/apps/app_0/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -classpath /opt/apps/app_0/bin/bootstrap.jar:/opt/apps/app_0/bin/tomcat-juli.jar -Dcatalina.base=/opt/apps/app_0 -Dcatalina.home=/opt/apps/app_0 -Djava.io.tmpdir=/opt/apps/app_0/temp org.apache.catalina.startup.Bootstrap start
root 7816 7769 0 22:25 pts/0 00:00:00 tail -f logs/catalina.out
[root@docker_host_0 opt]#
[root@docker_host_0 opt]# docker container port app_man
8080/tcp -> 0.0.0.0:8080
[root@docker_host_0 opt]#
[root@docker_host_0 opt]# docker container logs app_man
Using CATALINA_BASE: /opt/apps/app_0
Using CATALINA_HOME: /opt/apps/app_0
Using CATALINA_TMPDIR: /opt/apps/app_0/temp
Using JRE_HOME: /opt/jdks/jdk1.8.0_212
Using CLASSPATH: /opt/apps/app_0/bin/bootstrap.jar:/opt/apps/app_0/bin/tomcat-juli.jar
Tomcat started.
...
05-May-2019 22:25:55.060 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 521 ms
[root@docker_host_0 opt]#
[root@docker_host_0 opt]# ss -atn | grep 8080
LISTEN 0 128 :::8080 :::*
[root@docker_host_0 opt]#
发送请求,访问日志显示tomcat正常运行:
tomcat默认的访问日志以日期命名,形式为localhost_access_log.YYYY-MM-DD.txt
[root@docker_host_0 opt]# curl localhost:8080 &> /dev/null
[root@docker_host_0 opt]# docker exec -it app_man tail -f logs/localhost_access_log.$(date +%F).txt
172.17.0.1 - - [05/May/2019:22:31:47 +0000] "GET / HTTP/1.1" 200 11204
停止容器后,宿主机的端口映射关闭:
[root@docker_host_0 opt]# docker container stop app_man
app_man
[root@docker_host_0 opt]#
[root@docker_host_0 opt]# docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a5c1750f880c tomcat_app_manual "bash -c 'bin/startu…" 9 minutes ago Exited (137) 9 seconds ago app_man
e414c244d725 t_i_1 "bash -c 'bin/startu…" 15 minutes ago Created t_c_2
63258c74cb4b t_i_0 "/bin/bash" 17 minutes ago Exited (0) 17 minutes ago t_c_1
6a6a3ed5a380 centos "bash -c 'mkdir -p /…" 20 minutes ago Exited (0) 20 minutes ago t_c_0
[root@docker_host_0 opt]#
[root@docker_host_0 opt]# ss -atn | grep 8080
[root@docker_host_0 opt]#
3.1.2 自动构建
创建名称为Dockerfile的文件,并添加以下内容:
[root@docker_host_0 opt]# vi Dockerfile
FROM centos:latest
COPY apache-tomcat-8.5.40 /opt/apps/app_0
EXPOSE 8080
ENV JAVA_HOME /opt/jdks/jdk1.8.0_212
WORKDIR /opt/apps/app_0
CMD bin/startup.sh && tail -f logs/catalina.out
在Dockerfile所在目录下,执行build命令构建镜像,名称为tomcat_app_automatic:
[root@docker_host_0 opt]# docker build -t tomcat_app_automatic .
Sending build context to Docker daemon 219.1MB
Step 1/6 : FROM centos:latest
---> 9f38484d220f
Step 2/6 : COPY apache-tomcat-8.5.40 /opt/apps/app_0
---> a9ec389212f2
Step 3/6 : EXPOSE 8080
---> Running in b52093559f48
Removing intermediate container b52093559f48
---> 7e52baca9d55
Step 4/6 : ENV JAVA_HOME /opt/jdks/jdk1.8.0_212
---> Running in a39dfd747133
Removing intermediate container a39dfd747133
---> 9d735d4bf9b1
Step 5/6 : WORKDIR /opt/apps/app_0
---> Running in 5137688b2b8e
Removing intermediate container 5137688b2b8e
---> c7bf4a13f5ef
Step 6/6 : CMD bin/startup.sh && tail -f logs/catalina.out
---> Running in 6e234908cd40
Removing intermediate container 6e234908cd40
---> 88d50ce0f132
Successfully built 88d50ce0f132
Successfully tagged tomcat_app_automatic:latest
[root@docker_host_0 opt]#
REPOSITORY与TAG为<none>的镜像为自动构建过程中生成的中间层,每一层对应一条Dockerfile指令:
[root@docker_host_0 opt]# docker image ls -a
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat_app_automatic latest 88d50ce0f132 5 minutes ago 216MB
<none> <none> a9ec389212f2 5 minutes ago 216MB
<none> <none> 9d735d4bf9b1 5 minutes ago 216MB
<none> <none> 7e52baca9d55 5 minutes ago 216MB
<none> <none> c7bf4a13f5ef 5 minutes ago 216MB
tomcat_app_manual latest 557c9112cb3f 24 minutes ago 216MB
t_i_1 latest c5f0d673d958 26 minutes ago 216MB
t_i_0 latest 1aa86a5d25c2 28 minutes ago 216MB
centos latest 9f38484d220f 7 weeks ago 202MB
[root@docker_host_0 opt]#
[root@docker_host_0 opt]#
[root@docker_host_0 opt]# docker image inspect --format='{{ .ContainerConfig.Cmd }}' 9d735d4bf9b1
[/bin/sh -c #(nop) ENV JAVA_HOME=/opt/jdks/jdk1.8.0_212]
[root@docker_host_0 opt]# docker image inspect --format='{{ .ContainerConfig.Cmd }}' a9ec389212f2
[/bin/sh -c #(nop) COPY dir:2e81cf3513b112d6ce6d7132e7bca23162bdba7cbf381d72f1b9a7a42c87f19d in /opt/apps/app_0 ]
[root@docker_host_0 opt]# docker image inspect --format='{{ .ContainerConfig.Cmd }}' 7e52baca9d55
[/bin/sh -c #(nop) EXPOSE 8080]
[root@docker_host_0 opt]# docker image inspect --format='{{ .ContainerConfig.Cmd }}' c7bf4a13f5ef
[/bin/sh -c #(nop) WORKDIR /opt/apps/app_0]
[root@docker_host_0 opt]# docker image inspect --format='{{ .ContainerConfig.Cmd }}' tomcat_app_automatic
[/bin/sh -c #(nop) CMD ["/bin/sh" "-c" "bin/startup.sh && tail -f logs/catalina.out"]]
[root@docker_host_0 opt]#
以名称app_auto启动tomcat_app_automatic镜像:
[root@docker_host_0 opt]# docker run -dit --name app_auto -p 8080:8080 --mount src=jdks,dst=/opt/jdks,ro tomcat_app_automatic
57878e669fb99606f85dccf6937a43babaa23c327040c7994657fab2ac0e5acb
[root@docker_host_0 opt]#
[root@docker_host_0 opt]# docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
57878e669fb9 tomcat_app_automatic "/bin/sh -c 'bin/sta…" 5 seconds ago Up 4 seconds 0.0.0.0:8080->8080/tcp app_auto
a5c1750f880c tomcat_app_manual "bash -c 'bin/startu…" 22 minutes ago Exited (137) 13 minutes ago app_man
e414c244d725 t_i_1 "bash -c 'bin/startu…" 28 minutes ago Created t_c_2
63258c74cb4b t_i_0 "/bin/bash" 30 minutes ago Exited (0) 30 minutes ago t_c_1
6a6a3ed5a380 centos "bash -c 'mkdir -p /…" 33 minutes ago Exited (0) 33 minutes ago t_c_0
[root@docker_host_0 opt]#
[root@docker_host_0 opt]# docker container top app_auto
UID PID PPID C STIME TTY TIME CMD
root 8305 8287 0 22:48 pts/0 00:00:00 /bin/sh -c bin/startup.sh && tail -f logs/catalina.out
root 8352 8305 3 22:48 pts/0 00:00:02 /opt/jdks/jdk1.8.0_212/bin/java -Djava.util.logging.config.file=/opt/apps/app_0/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -classpath /opt/apps/app_0/bin/bootstrap.jar:/opt/apps/app_0/bin/tomcat-juli.jar -Dcatalina.base=/opt/apps/app_0 -Dcatalina.home=/opt/apps/app_0 -Djava.io.tmpdir=/opt/apps/app_0/temp org.apache.catalina.startup.Bootstrap start
root 8353 8305 0 22:48 pts/0 00:00:00 tail -f logs/catalina.out
[root@docker_host_0 opt]#
[root@docker_host_0 opt]# docker container port app_auto
8080/tcp -> 0.0.0.0:8080
[root@docker_host_0 opt]#
[root@docker_host_0 opt]# ss -atn | grep 8080
LISTEN 0 128 :::8080 :::*
[root@docker_host_0 opt]#
发送请求并查看日志:
[root@docker_host_0 opt]# curl localhost:8080 &> /dev/null
[root@docker_host_0 opt]#
[root@docker_host_0 opt]# docker exec -it app_auto tail -f logs/localhost_access_log.$(date +%F).txt
172.17.0.1 - - [05/May/2019:22:52:28 +0000] "GET / HTTP/1.1" 200 11204
查看app_auto容器的运行参数:
[root@docker_host_0 opt]# docker container inspect --format='{{ .Config.Env }}' app_auto
[PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin JAVA_HOME=/opt/jdks/jdk1.8.0_212]
[root@docker_host_0 opt]# docker container inspect --format='{{ .Config.ExposedPorts }}' app_auto
map[8080/tcp:{}]
[root@docker_host_0 opt]# docker container inspect --format='{{ .Config.WorkingDir }}' app_auto
/opt/apps/app_0
[root@docker_host_0 opt]# docker container inspect --format='{{ .Config.Cmd }}' app_auto
[/bin/sh -c bin/startup.sh && tail -f logs/catalina.out]
[root@docker_host_0 opt]#
对比两种构建方式,初始状态(centos镜像)与最终状态(tomcat镜像)相同,且目标镜像的大小与运行结果相同。自动构建无需关注中间细节,仅需将功能对应的指令与参数写入到文件,构建过程由docker完成,且自动移除构建过程中产生的中间过渡容器。
Dockerfile中的每一条指令均可以对应到手动构建的命令行选项/参数:
- docker run centos对应于FROM centos
- docker cp对应于COPY
- --expose对应于EXPOST
- --workdir对应于WORKDIR
- --env对应于ENV
- docker container create命令对应于CMD
3.2 迁移
- export与save命令分别以容器与镜像标识作为参数,将容器与镜像以tar包的形式导出。两条命令默认将结果输出至STDOUT,可以通过输出重定向或-o/--output选项写入到指定的文件。
- import命令与load命令将容器与镜像的tar包导入为本地镜像。load命令默认从STDIN读取tar包内容,可以通过输入重定向或-i/--input选项读取指定的文件;import命令直接以tar包文件名为参数进行导入。
- export导出的容器tar包中,包含可写层中的磁盘文件变更,但不包含镜像构建时指定的参数,包括工作目录与环境变量等信息。import导入容器时可以通过-c/--change选项指定Dockerfile指令,每个选项对应一条双引号内的指令,形式为docker import -c "WORKDIR /opt" -c "EVN JAVA_HOME /opt" 容器tar包。
- 执行导入与导出操作时,应注意命令与操作对象的匹配,如export命令的操作对象为容器而非镜像,save命令的操作对象为镜像而非容器;此外,export命令与save命令导出的tar包中所含的信息不同,因此export/save命令的输出应与import/load命令的输入严格对应。对export导出的容器tar包执行load,或对save导出的镜像tar包执行import,都将导入失败,或导入成功但运行容器失败,以及导致其他未知行为。
将容器app_auto导出为app_ctr.tar,镜像tomcat_app_automatic导出为app_img.tar。若对export命令指定镜像标识,以及对save命令指定容器标识,则提示容器或镜像不存在,导出失败。
[root@docker_host_0 opt]# docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
57878e669fb9 tomcat_app_automatic "/bin/sh -c 'bin/sta…" 11 minutes ago Up 11 minutes 0.0.0.0:8080->8080/tcp app_auto
a5c1750f880c tomcat_app_manual "bash -c 'bin/startu…" 33 minutes ago Exited (137) 24 minutes ago app_man
e414c244d725 t_i_1 "bash -c 'bin/startu…" 40 minutes ago Created t_c_2
63258c74cb4b t_i_0 "/bin/bash" 42 minutes ago Exited (0) 42 minutes ago t_c_1
6a6a3ed5a380 centos "bash -c 'mkdir -p /…" 45 minutes ago Exited (0) 45 minutes ago t_c_0
[root@docker_host_0 opt]#
[root@docker_host_0 opt]# docker image ls -a
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat_app_automatic latest 88d50ce0f132 20 minutes ago 216MB
<none> <none> 9d735d4bf9b1 20 minutes ago 216MB
<none> <none> 7e52baca9d55 20 minutes ago 216MB
<none> <none> a9ec389212f2 20 minutes ago 216MB
<none> <none> c7bf4a13f5ef 20 minutes ago 216MB
tomcat_app_manual latest 557c9112cb3f 39 minutes ago 216MB
t_i_1 latest c5f0d673d958 41 minutes ago 216MB
t_i_0 latest 1aa86a5d25c2 43 minutes ago 216MB
centos latest 9f38484d220f 7 weeks ago 202MB
[root@docker_host_0 opt]#
[root@docker_host_0 opt]# docker save app_auto > app_img.tar
Error response from daemon: No such image: app_auto
[root@docker_host_0 opt]#
[root@docker_host_0 opt]# docker export tomcat_app_automatic -o app_ctr.tar
Error response from daemon: No such container: tomcat_app_automatic
[root@docker_host_0 opt]#
[root@docker_host_0 opt]# docker export app_auto -o app_ctr.tar
[root@docker_host_0 opt]# docker save tomcat_app_automatic -o app_img.tar
[root@docker_host_0 opt]#
[root@docker_host_0 opt]# ll -h app_ctr.tar app_img.tar
-rw------- 1 root root 214M May 5 23:01 app_ctr.tar
-rw------- 1 root root 214M May 5 23:02 app_img.tar
[root@docker_host_0 opt]#
将两个tar包传输至另一宿主机(docker_host_1),对镜像tar包执行load命令,导入成功,但镜像运行失败:
[root@docker_host_1 opt]# ll -h app_ctr.tar app_img.tar
-rw------- 1 root root 214M May 5 23:06 app_ctr.tar
-rw------- 1 root root 214M May 5 23:06 app_img.tar
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# docker import app_img.tar app_img:new
sha256:38c69e443d6ff4712e22fcfb4a306776b064a12b3ae1165d5cd725c5dfc4a202
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# docker image ls -a
REPOSITORY TAG IMAGE ID CREATED SIZE
app_img new 38c69e443d6f 6 seconds ago 224MB
centos latest 9f38484d220f 7 weeks ago 202MB
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# docker run -it --rm app_img:new /bin/bash
docker: Error response from daemon: OCI runtime create failed: container_linux.go:345: starting container process caused "exec: \"/bin/bash\": stat /bin/bash: no such file or directory": unknown.
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# docker image rm -f app_img:new
Untagged: app_img:new
Deleted: sha256:38c69e443d6ff4712e22fcfb4a306776b064a12b3ae1165d5cd725c5dfc4a202
Deleted: sha256:1e2b7840068294c8c3f1c67cc0d7939eb6ac2135afab7f1065616d9c5c852bd5
[root@docker_host_1 opt]#
对镜像tar包执行load操作,提示找不到所需的文件,导入失败:
[root@docker_host_1 opt]# docker load -i app_ctr.tar
open /var/lib/docker/tmp/docker-import-466818323/dev/json: no such file or directory
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# docker image ls -a
REPOSITORY TAG IMAGE ID CREATED SIZE
centos latest 9f38484d220f 7 weeks ago 202MB
[root@docker_host_1 opt]#
[root@docker_host_1 opt]#
将容器tar包导入为app_ctr:new,生成的本地镜像中不包含导入前的运行时参数,包括环境变量,开放端口,工作目录与命令,因此容器内的tomcat进程未启动,无法按导入前的状态运行。
[root@docker_host_1 opt]# docker import app_ctr.tar app_ctr:new
sha256:dd4c6121da0e03db43892da94fdb02ee6b0fe5a6e7982f7e40bc37a398497ded
[root@docker_host_1 opt]# docker image ls -a
REPOSITORY TAG IMAGE ID CREATED SIZE
app_ctr new dd4c6121da0e 4 seconds ago 216MB
centos latest 9f38484d220f 7 weeks ago 202MB
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# docker run -dit --name app_ctr_0 --mount src=jdks,dst=/opt/jdks,ro -p 8080:8080 app_ctr:new
docker: Error response from daemon: No command specified.
See 'docker run --help'.
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# docker run -dit --name app_ctr_0 --mount src=jdks,dst=/opt/jdks,ro -p 8080:8080 app_ctr:new /bin/bash
6dd2d5243b271259d0f6120aebfc697b280add80b423e5ebf26cbbdf2e597941
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# docker container top app_ctr_0
UID PID PPID C STIME TTY TIME CMD
root 7678 7660 0 23:11 pts/0 00:00:00 /bin/bash
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# docker container logs app_ctr_0
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# ss -atn | grep 8080
LISTEN 0 128 :::8080 :::*
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# docker container port app_ctr_0
8080/tcp -> 0.0.0.0:8080
[root@docker_host_1 opt]#
再次导入容器tar包,名称为app_ctr:latest,并指定运行时的参数。运行镜像后,tomcat启动,并可正常访问:
[root@docker_host_1 opt]# docker import app_ctr.tar -c "ENV JAVA_HOME /opt/jdks/jdk1.8.0_212" -c "WORKDIR /opt/apps/app_0" -c "EXPOSE 8080" -c "CMD bin/startup.sh && tail -f logs/catalina.out" app_ctr:latest
sha256:c39af6a5bff5bd1069bb89dec43ea32ade37a356fd05113a6003f7c3ee178863
[root@docker_host_1 opt]#
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# docker image ls -a
REPOSITORY TAG IMAGE ID CREATED SIZE
app_ctr latest c39af6a5bff5 10 seconds ago 216MB
app_ctr new dd4c6121da0e 4 minutes ago 216MB
centos latest 9f38484d220f 7 weeks ago 202MB
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# docker image inspect --format='{{ .Config.Env }}' app_ctr:latest
[JAVA_HOME=/opt/jdks/jdk1.8.0_212]
[root@docker_host_1 opt]# docker image inspect --format='{{ .Config.ExposedPorts }}' app_ctr:latest
map[8080/tcp:{}]
[root@docker_host_1 opt]# docker image inspect --format='{{ .Config.WorkingDir }}' app_ctr:latest
/opt/apps/app_0
[root@docker_host_1 opt]# docker image inspect --format='{{ .Config.Cmd }}' app_ctr:latest
[/bin/sh -c bin/startup.sh && tail -f logs/catalina.out]
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# docker container stop app_ctr_0
app_ctr_0
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# docker run -dit --name app_ctr_1 --mount src=jdks,dst=/opt/jdks,ro -p 8080:8080 app_ctr:latest
169fce93e085598ffeb188d4861cc4f62aa8cc14b380da6f6397f32f38b8751e
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# docker container top app_ctr_1
UID PID PPID C STIME TTY TIME CMD
root 7960 7943 0 23:18 pts/0 00:00:00 /bin/sh -c bin/startup.sh && tail -f logs/catalina.out
root 8008 7960 18 23:18 pts/0 00:00:02 /opt/jdks/jdk1.8.0_212/bin/java -Djava.util.logging.config.file=/opt/apps/app_0/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -classpath /opt/apps/app_0/bin/bootstrap.jar:/opt/apps/app_0/bin/tomcat-juli.jar -Dcatalina.base=/opt/apps/app_0 -Dcatalina.home=/opt/apps/app_0 -Djava.io.tmpdir=/opt/apps/app_0/temp org.apache.catalina.startup.Bootstrap start
root 8009 7960 0 23:18 pts/0 00:00:00 tail -f logs/catalina.out
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# ss -atn | grep 8080
LISTEN 0 128 :::8080 :::*
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# docker container logs app_ctr_
Error: No such container: app_ctr_
[root@docker_host_1 opt]# docker container logs app_ctr_
app_ctr_0 app_ctr_1
[root@docker_host_1 opt]# docker container logs app_ctr_1
Using CATALINA_BASE: /opt/apps/app_0
Using CATALINA_HOME: /opt/apps/app_0
Using CATALINA_TMPDIR: /opt/apps/app_0/temp
Using JRE_HOME: /opt/jdks/jdk1.8.0_212
Using CLASSPATH: /opt/apps/app_0/bin/bootstrap.jar:/opt/apps/app_0/bin/tomcat-juli.jar
Tomcat started.
...
05-May-2019 23:18:37.452 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 628 ms
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# curl localhost:8080 &> /dev/null
[root@docker_host_1 opt]# docker exec -it app_ctr_1 tail -n 1 logs/localhost_access_log.$(date +%F).txt
192.168.9.1 - - [05/May/2019:23:20:00 +0000] "GET /favicon.ico HTTP/1.1" 200 21630
[root@docker_host_1 opt]#
导入镜像tar包app_img.tar,生成的本地镜像中包含所有导入前的配置参数,包括REPOSITORY,TAG,环境变量,工作目录,开放端口以及运行命令,因此挂载命名卷并运行后,结果与导入前相同:
[root@docker_host_1 opt]# docker container stop app_ctr_1
app_ctr_1
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# docker load -i app_img.tar
83a1de39c1af: Loading layer 14.39MB/14.39MB
Loaded image: tomcat_app_automatic:latest
[root@docker_host_1 opt]# docker image ls -a
REPOSITORY TAG IMAGE ID CREATED SIZE
app_ctr latest c39af6a5bff5 6 minutes ago 216MB
app_ctr new dd4c6121da0e 11 minutes ago 216MB
tomcat_app_automatic latest 88d50ce0f132 42 minutes ago 216MB
centos latest 9f38484d220f 7 weeks ago 202MB
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# docker image inspect --format='{{ .Config.Env }}' tomcat_app_automatic
[PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin JAVA_HOME=/opt/jdks/jdk1.8.0_212]
[root@docker_host_1 opt]# docker image inspect --format='{{ .Config.WorkingDir }}' tomcat_app_automatic
/opt/apps/app_0
[root@docker_host_1 opt]# docker image inspect --format='{{ .Config.ExposedPorts }}' tomcat_app_automatic
map[8080/tcp:{}]
[root@docker_host_1 opt]# docker image inspect --format='{{ .Config.Cmd }}' tomcat_app_automatic
[/bin/sh -c bin/startup.sh && tail -f logs/catalina.out]
[root@docker_host_1 opt]#
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# docker run -dit --name app_img_0 --mount src=jdks,dst=/opt/jdks,ro -p 8080:8080 tomcat_app_automatic
0193ebdcbf00d688072536162a38ff4f788402d0cc8428c58481a0201151bca0
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0193ebdcbf00 tomcat_app_automatic "/bin/sh -c 'bin/sta…" 8 seconds ago Up 7 seconds 0.0.0.0:8080->8080/tcp app_img_0
169fce93e085 app_ctr:latest "/bin/sh -c 'bin/sta…" 4 minutes ago Exited (137) 49 seconds ago app_ctr_1
6dd2d5243b27 app_ctr:new "/bin/bash" 11 minutes ago Exited (137) 4 minutes ago app_ctr_0
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# docker container top app_img_0
UID PID PPID C STIME TTY TIME CMD
root 8455 8437 0 23:22 pts/0 00:00:00 /bin/sh -c bin/startup.sh && tail -f logs/catalina.out
root 8502 8455 7 23:22 pts/0 00:00:02 /opt/jdks/jdk1.8.0_212/bin/java -Djava.util.logging.config.file=/opt/apps/app_0/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -classpath /opt/apps/app_0/bin/bootstrap.jar:/opt/apps/app_0/bin/tomcat-juli.jar -Dcatalina.base=/opt/apps/app_0 -Dcatalina.home=/opt/apps/app_0 -Djava.io.tmpdir=/opt/apps/app_0/temp org.apache.catalina.startup.Bootstrap start
root 8503 8455 0 23:22 pts/0 00:00:00 tail -f logs/catalina.out
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# ss -atn | grep 8080
LISTEN 0 128 :::8080 :::*
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# curl localhost:8080 &> /dev/null
[root@docker_host_1 opt]#
[root@docker_host_1 opt]# docker exec -it app_img_0 tail -f logs/localhost_access_log.$(date +%F).txt
172.17.0.1 - - [05/May/2019:23:23:24 +0000] "GET / HTTP/1.1" 200 11204
参考
https://docs.docker.com/engine/reference/commandline/docker/
https://docs.docker.com/engine/reference/builder/