A 构建镜像
1 创建方式
-
更新镜像:使用docker commit命令
-
构建镜像:使用docker build命令,需要创建Dockerfile文件
2 Dockerfile
Dockerfile是用来构建Docker镜像的文件,是由一系列指令和参数构成的脚本,从FROM命令开始,紧接着各种命令、参数等,最终会生成一个新的镜像。
第一条指令必须是FROM,指定Base Image基础镜像,指令按从上往下的顺序,依次执行,每条指令都会创建一个新的镜像层并提交
FROM:指定基础镜像,即当前新镜像是基于哪个镜像的
MAINTAINER:指定作者
RUN:指定镜像构建过程中要运行的命令
ENV:设置环境变量
WORKDIR:指定默认的工作目录,即进入容器后默认进入的目录
VOLUME:创建挂载点,也称容器数据卷,用于数据共享和持久化
CMD:指定容器启动时要运行的命令,与RUN不同的是, 这些命令不是在镜像构建过程中执行的
ENTRYPOINT:指定容器启动时要运行的命令
COPY:拷贝文件/目录到镜像中
ADD:拷贝文件到镜像中,且会自动解压缩
EXPOSE:指定对外暴露的端口
分析Dockerfile
分析Dockerfile(tomcat:8.5.16-jre8)如下
原文地址:https://www.cnblogs.com/dfengwei/p/7144937.html
Dockerfile地址:https://github.com/docker-library/tomcat/blob/master/8.5/jre8/Dockerfile
注意,这里以master分支的Dockerfile链接为例,和DockerHub上的Dockerfile链接可能会不一致
#本镜像的基础镜像。有兴趣的话,可以自行在DockerHub上搜索openjdk,分析官方的openjdk镜像的Dockerfile文件。这里为什么不用oracle提供的jdk(jre)?简单地讲,版权问题。
FROM openjdk:8-jre
#声明CATALINA_HOME环境变量,这个变量大家都了解。
ENV CATALINA_HOME /usr/local/tomcat
#将Tomcat下的bin路径加入到PATH环境变量中。
ENV PATH $CATALINA_HOME/bin:$PATH
#创建tomcat路径。
RUN mkdir -p "$CATALINA_HOME"
#指定RUN、CMD、ENTRYPOINT命令的当前工作路径。
WORKDIR $CATALINA_HOME
#Tomcat Native路径配置。
ENV TOMCAT_NATIVE_LIBDIR $CATALINA_HOME/native-jni-lib
#将TOMCAT_NATIVE_LIBDIR加入到LD_LIBRARY_PATH环境变量中,这样Tomcat在查找Tomcat Native相关的动态链接库时,会去查找TOMCAT_NATIVE_LIBDIR环境变量指定的路径。
ENV LD_LIBRARY_PATH ${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$TOMCAT_NATIVE_LIBDIR
#检查、更新OpenSSL,这块的细节我没深究。
ENV OPENSSL_VERSION 1.1.0f-3
RUN { \
echo 'deb http://deb.debian.org/debian stretch main'; \
} > /etc/apt/sources.list.d/stretch.list \
&& { \
echo 'Package: *'; \
echo 'Pin: release n=stretch'; \
echo 'Pin-Priority: -10'; \
echo; \
echo 'Package: openssl libssl*'; \
echo "Pin: version $OPENSSL_VERSION"; \
echo 'Pin-Priority: 990'; \
} > /etc/apt/preferences.d/stretch-openssl
RUN apt-get update && apt-get install -y --no-install-recommends \
libapr1 \
openssl="$OPENSSL_VERSION" \
&& rm -rf /var/lib/apt/lists/*
#从key服务器导入key,用于验证tomcat压缩文件的签名,这块也没深究。
ENV GPG_KEYS 05AB33110949707C93A279E3D3EFE6B686867BA6 07E48665A34DCAFAE522E5E6266191C37C037D42 47309207D818FFD8DCD3F83F1931D684307A10A5 541FBE7D8F78B25E055DDEE13C370389288584E7 61B832AC2F1C5A90F0F9B00A1C506407564C17A3 713DA88BE50911535FE716F5208B0AB1D63011C7 79F7026C690BAA50B92CD8B66A3AD3F4F22C4FED 9BA44C2621385CB966EBA586F72C284D731FABEE A27677289986DB50844682F8ACB77FC2E86E29AC A9C5DF4D22E99998D9875A5110C01C5A2F6059E7 DCFD35E0BF8CA7344752DE8B6FB21E8933C60243 F3A04C595DB5B6A5F1ECA43E3B7BBB100D811BBE F7DA48BB64BCB84ECBA7EE6935CD23C10D498E23
RUN set -ex; \
for key in $GPG_KEYS; do \
gpg --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; \
done
#Tomcat相关文件的版本。
ENV TOMCAT_MAJOR 8
ENV TOMCAT_VERSION 8.5.16
#Tomcat相关文件下载地址。
ENV TOMCAT_TGZ_URL https://www.apache.org/dyn/closer.cgi?action=download&filename=tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz
ENV TOMCAT_ASC_URL https://www.apache.org/dist/tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz.asc
#执行命令
RUN set -x \
\
#下载Tomcat压缩文件
&& wget -O tomcat.tar.gz "$TOMCAT_TGZ_URL" \
&& wget -O tomcat.tar.gz.asc "$TOMCAT_ASC_URL" \
#进行签名验证
&& gpg --batch --verify tomcat.tar.gz.asc tomcat.tar.gz \
#解压Tomcat
&& tar -xvf tomcat.tar.gz --strip-components=1 \
# 删除供Windows系统使用的.bat文件
&& rm bin/*.bat \
# 删除压缩文件
&& rm tomcat.tar.gz* \
\
#安装Tomcat Native
&& nativeBuildDir="$(mktemp -d)" \
&& tar -xvf bin/tomcat-native.tar.gz -C "$nativeBuildDir" --strip-components=1 \
&& nativeBuildDeps=" \
dpkg-dev \
gcc \
libapr1-dev \
libssl-dev \
make \
openjdk-${JAVA_VERSION%%[-~bu]*}-jdk=$JAVA_DEBIAN_VERSION \
" \
&& apt-get update && apt-get install -y --no-install-recommends $nativeBuildDeps && rm -rf /var/lib/apt/lists/* \
&& ( \
export CATALINA_HOME="$PWD" \
&& cd "$nativeBuildDir/native" \
&& gnuArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)" \
&& ./configure \
--build="$gnuArch" \
--libdir="$TOMCAT_NATIVE_LIBDIR" \
--prefix="$CATALINA_HOME" \
--with-apr="$(which apr-1-config)" \
--with-java-home="$(docker-java-home)" \
--with-ssl=yes \
&& make -j "$(nproc)" \
&& make install \
) \
&& apt-get purge -y --auto-remove $nativeBuildDeps \
&& rm -rf "$nativeBuildDir" \
&& rm bin/tomcat-native.tar.gz
#验证Tomcat Native是否安装成功
RUN set -e \
&& nativeLines="$(catalina.sh configtest 2>&1)" \
&& nativeLines="$(echo "$nativeLines" | grep 'Apache Tomcat Native')" \
&& nativeLines="$(echo "$nativeLines" | sort -u)" \
&& if ! echo "$nativeLines" | grep 'INFO: Loaded APR based Apache Tomcat Native library' >&2; then \
echo >&2 "$nativeLines"; \
exit 1; \
fi
#暴露8080端口
EXPOSE 8080
#容器启动时执行的命令。
CMD ["catalina.sh", "run"]
此Dockerfile的主要功能可归纳为:
- 以openjdk镜像为基础镜像进行构建。
- 安装Tomcat Native,及其依赖库(比如APR、OpenSSL等)。验证是否正确安装。
- 下载Tomcat,检查签名,解压、清除无用文件等。
- 暴露8080端口,配置入口命令。
3 自定义tomcat镜像
原文地址:https://www.cnblogs.com/uncleyong/p/8894133.html
3.1 创建Dockerfile文件
[root@localhost mydocker]# pwd
/data/mydocker
[root@localhost mydocker]# ll
total 193708
-rw-r--r-- 1 root root 10835556 Apr 12 2019 apache-tomcat-9.0.19.tar.gz
-rwxr--r-- 1 root root 446 Dec 20 16:44 Dockerfile
-rwxr--r-- 1 root root 187513052 Dec 20 16:35 openjdk-11.0.2_linux-x64_bin.tar.gz
Dockerfile文件内容
FROM centos
MAINTAINER testname
# 拷贝文件
ADD openjdk-11.0.2_linux-x64_bin.tar.gz /usr/local
ADD apache-tomcat-9.0.19.tar.gz /usr/local
# 配置环境变量
ENV JAVA_HOME /usr/local/jdk-11.0.2
ENV CLASSPATH .:$JAVA_HOME/lib
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.19
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin
WORKDIR $CATALINA_HOME
EXPOSE 8080
# 镜像运行容器就把tomcat启动起来
CMD ["catalina.sh", "run"]
3.2 docker build
查看docker build使用方法
docker build --help
执行docker build -t (tag名)
[root@localhost mydocker]# docker build -t zhang/tomcat:1.0 .
Sending build context to Docker daemon 198.4MB
Step 1/11 : FROM centos
latest: Pulling from library/centos
a1d0c7532777: Pull complete
Digest: sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177
Status: Downloaded newer image for centos:latest
---> 5d0da3dc9764
Step 2/11 : MAINTAINER zhanglei
---> Running in df0dfb66a62d
Removing intermediate container df0dfb66a62d
---> 1e7053949435
Step 3/11 : ADD openjdk-11.0.2_linux-x64_bin.tar.gz /usr/local
---> 9b98a2af2ef3
Step 4/11 : ADD apache-tomcat-9.0.19.tar.gz /usr/local
---> 513dc1c01353
Step 5/11 : ENV JAVA_HOME /usr/local/jdk-11.0.2
---> Running in 91e95bd841be
Removing intermediate container 91e95bd841be
---> 39c98b82022f
Step 6/11 : ENV CLASSPATH .:$JAVA_HOME/lib
---> Running in f59e05ae989e
Removing intermediate container f59e05ae989e
---> edc68b5e462c
Step 7/11 : ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.19
---> Running in b22b8f0298a1
Removing intermediate container b22b8f0298a1
---> 2841c3a092c9
Step 8/11 : ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin
---> Running in f6ebcd63c8c2
Removing intermediate container f6ebcd63c8c2
---> 6580c4b7e4e5
Step 9/11 : WORKDIR $CATALINA_HOME
---> Running in 8af75ddd7f62
Removing intermediate container 8af75ddd7f62
---> caedcd4bd116
Step 10/11 : EXPOSE 8080
---> Running in b0353ea35616
Removing intermediate container b0353ea35616
---> 27d1ab33db33
Step 11/11 : CMD ["catalina.sh", "run"]
---> Running in 7281f2f1e31a
Removing intermediate container 7281f2f1e31a
---> b0c823dc19cc
Successfully built b0c823dc19cc
Successfully tagged zhang/tomcat:1.0
[root@localhost mydocker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
zhang/tomcat 1.0 b0c823dc19cc 9 seconds ago 556MB
centos latest 5d0da3dc9764 3 months ago 231MB
gogs/gogs latest 8ec7cc11f4a3 7 months ago 93.9MB
运行容器
docker run \
--name zhang_tomcat \
-p 8181:8080 \
-d zhang/tomcat:1.0
访问url,成功显示tomcat主页,创建镜像成功!
B Dockfile指令详解
参考资料:https://www.yuque.com/grasilife/docker/image-dockerfile-readme
1 COPY 复制文件
格式:
- COPY <源路径>... <目标路径>
- COPY ["<源路径1>",... "<目标路径>"]
和 RUN 指令一样,也有两种格式,一种类似于命令行,一种类似于函数调用。
COPY 指令将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置。比如:
COPY package.json /usr/src/app/
<源路径> 可以是多个,甚至可以是通配符,其通配符规则要满足 Go 的 filepath.Match 规则,如:
COPY hom* /mydir/
COPY hom?.txt /mydir/
<目标路径> 可以是容器内的绝对路径,也可以是相对于工作目录的相对路径(工作目录可以用 WORKDIR 指令来指定)。
目标路径不需要事先创建,如果目录不存在会在复制文件前先行创建缺失目录。
此外,还需要注意一点,使用 COPY 指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等。
这个特性对于镜像定制很有用。特别是构建相关文件都在使用 Git 进行管理的时候。
2 ADD 更高级的复制文件
ADD 指令和 COPY 的格式和性质基本一致。但是在 COPY 基础上增加了一些功能。
比如 <源路径> 可以是一个 URL,这种情况下,Docker 引擎会试图去下载这个链接的文件放到 <目标路径> 去。
下载后的文件权限自动设置为600,如果这并不是想要的权限,那么还需要增加额外的一层 RUN 进行权限调整,另外,如果下载的是个压缩包,需要解压缩,也一样还需要额外的一层 RUN 指令进行解压缩。
所以不如直接使用 RUN 指令,然后使用 wget 或者 curl 工具下载,处理权限、解压缩、然后清理无用文件更合理。
因此,这个功能其实并不实用,而且不推荐使用。
如果 <源路径> 为一个 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,ADD 指令将会自动解压缩这个压缩文件到 <目标路径> 去。
在某些情况下,这个自动解压缩的功能非常有用,比如官方镜像 ubuntu 中:
FROM scratch
ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz /
...
但在某些情况下,如果我们真的是希望复制个压缩文件进去,而不解压缩,这时就不可以使用 ADD 命令了。
在 Docker 官方的 Dockerfile 最佳实践文档 中要求,尽可能的使用 COPY,因为 COPY 的语义很明确,就是复制文件而已,而 ADD 则包含了更复杂的功能,其行为也不一定很清晰。最适合使用 ADD 的场合,就是所提及的需要自动解压缩的场合。
另外需要注意的是,ADD 指令会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。
因此在 COPY 和 ADD 指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用 COPY 指令,仅在需要自动解压缩的场合使用 ADD。
3 CMD 容器启动命令
CMD 指令的格式和 RUN 相似,也是两种格式:
- shell 格式:CMD <命令>
- exec 格式:CMD ["可执行文件", "参数1", "参数2"...]
- 参数列表格式:CMD ["参数1", "参数2"...]。在指定了 ENTRYPOINT 指令后,用 CMD 指定具体的参数。
之前介绍容器的时候曾经说过,Docker 不是虚拟机,容器就是进程。
既然是进程,那么在启动容器的时候,需要指定所运行的程序及参数。
CMD 指令就是用于指定默认的容器主进程的启动命令的。
在运行时可以指定新的命令来替代镜像设置中的这个默认命令,比如,ubuntu 镜像默认的 CMD 是 /bin/bash,如果我们直接 docker run -it ubuntu 的话,会直接进入 bash。
我们也可以在运行时指定运行别的命令,如 docker run -it ubuntu cat /etc/os-release。
这就是用 cat /etc/os-release 命令替换了默认的 /bin/bash 命令了,输出了系统版本信息。
在指令格式上,一般推荐使用 exec 格式,这类格式在解析时会被解析为 JSON 数组,因此一定要使用双引号 ",而不要使用单引号。
如果使用 shell 格式的话,实际的命令会被包装为 sh -c 的参数的形式进行执行。比如:
CMD echo $HOME
在实际执行中,会将其变更为:
CMD [ "sh", "-c", "echo $HOME" ]
这就是为什么我们可以使用环境变量的原因,因为这些环境变量会被 shell 进行解析处理。
提到 CMD 就不得不提容器中应用在前台执行和后台执行的问题。这是初学者常出现的一个混淆。
Docker 不是虚拟机,容器中的应用都应该以前台执行,而不是像虚拟机、物理机里面那样,用 upstart/systemd 去启动后台服务,容器内没有后台服务的概念。
一些初学者将 CMD 写为:
CMD service nginx start
然后发现容器执行后就立即退出了。甚至在容器内去使用 systemctl 命令结果却发现根本执行不了。
这就是因为没有搞明白前台、后台的概念,没有区分容器和虚拟机的差异,依旧在以传统虚拟机的角度去理解容器。
对于容器而言,其启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出,其它辅助进程不是它需要关心的东西。
而使用 service nginx start 命令,则是希望 upstart 来以后台守护进程形式启动 nginx 服务。
而刚才说了 CMD service nginx start 会被理解为 CMD [ "sh", "-c", "service nginx start"],因此主进程实际上是 sh。那么当 service nginx start 命令结束后,sh 也就结束了,sh 作为主进程退出了,自然就会令容器退出。
正确的做法是直接执行 nginx 可执行文件,并且要求以前台形式运行。比如:
CMD ["nginx", "-g", "daemon off;"]
4 VOLUME 定义匿名卷
- 格式为:VOLUME ["<路径1>", "<路径2>"...]
- VOLUME <路径>
之前我们说过,容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库文件应该保存于卷(volume)中,后面的章节我们会进一步介绍 Docker 卷的概念。为了防止运行时用户忘记将动态文件所保存目录挂载为卷,在 Dockerfile 中,我们可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会向容器存储层写入大量数据。
VOLUME /data
这里的 /data 目录就会在运行时自动挂载为匿名卷,任何向 /data
中写入的信息都不会记录进容器存储层,从而保证了容器存储层的无状态化。当然,运行时可以覆盖这个挂载设置。
比如:
docker run -d -v mydata:/data xxxx
在这行命令中,就使用了 mydata 这个命名卷挂载到了 /data 这个位置,替代了 Dockerfile 中定义的匿名卷的挂载配置。
C 更新镜像
1 进入指定容器伪终端
[root@localhost mydocker]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
25fae95b650c zhang/tomcat:1.0 "catalina.sh run" 3 hours ago Up 3 hours 0.0.0.0:8181->8080/tcp zhang_tomcat
[root@localhost mydocker]# docker exec -it 25fae95b650c /bin/bash
[root@25fae95b650c apache-tomcat-9.0.19]# pwd
/usr/local/apache-tomcat-9.0.19
[root@25fae95b650c apache-tomcat-9.0.19]# ls
BUILDING.txt CONTRIBUTING.md LICENSE NOTICE README.md RELEASE-NOTES RUNNING.txt bin conf lib logs temp webapps work
2 修改:这里复制了目录webapps,新目录名webapps_bak
[root@25fae95b650c apache-tomcat-9.0.19]# cp -r webapps webapps_bak
[root@25fae95b650c apache-tomcat-9.0.19]# ls
BUILDING.txt CONTRIBUTING.md LICENSE NOTICE README.md RELEASE-NOTES RUNNING.txt bin conf lib logs temp webapps webapps_bak work
[root@25fae95b650c apache-tomcat-9.0.19]# exit
3 docker commit
# 语法:docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
# -a :提交的镜像作者;
# -c :使用Dockerfile指令来创建镜像;
# -m :提交时的说明文字;
# -p :在commit时,将容器暂停。
[root@localhost mydocker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
zhang/tomcat 1.0 b0c823dc19cc 3 hours ago 556MB
centos latest 5d0da3dc9764 3 months ago 231MB
gogs/gogs latest 8ec7cc11f4a3 7 months ago 93.9MB
[root@localhost mydocker]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
25fae95b650c zhang/tomcat:1.0 "catalina.sh run" 3 hours ago Up 3 hours 0.0.0.0:8181->8080/tcp zhang_tomcat
[root@localhost mydocker]# docker commit -m='cp -r webapps webapps_bak' -a='zhanglei' 25fae95b650c zhang/tomcat:2.0
sha256:f375fea412a39898806339339442b55d8ee8e21b4a5874e518abb84298b1f446
[root@localhost mydocker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
zhang/tomcat 2.0 f375fea412a3 4 seconds ago 561MB
zhang/tomcat 1.0 b0c823dc19cc 3 hours ago 556MB
centos latest 5d0da3dc9764 3 months ago 231MB
gogs/gogs latest 8ec7cc11f4a3 7 months ago 93.9MB