Docker-Dockerfile构建学习
Dockerfile介绍
Dockerfile 是一个文本文件,其内包含了一条条的 指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
构建步骤分为:
- 编写一个
dockerfile
文件 docker build
构建成为一个镜像docker run
运行镜像docker pull
发布镜像(docker hub,阿里云镜像仓库等..)
Dockerfile 指令说明
指令 | 含义 |
---|---|
FROM 镜像 | 指定新镜像所基于的镜像,第一条指令必须为FROM指令,每创建一个镜像就需要一条FROM指令 |
MAINTAINER 名字 | 说明新镜像的维护人信息,姓名+邮箱-->gljadmin@199604.com |
RUN 命令 | 镜像构建时,执行的命令 |
CMD [“要运行的程序”,”参数1”,”参数2”] | 指令启动容器时要运行的命令或者脚本,Dockerfile只能有一条CMD命令,如果指定多条则只能最后一条被执行 |
ENTRYPOINT | 类似CMD命令,指定容器启动时候,需要运行的命令,可追加 |
EXPOSE 端口号 | 容器需要暴露的端口号,docker run -P 时,会自动随机映射 EXPOSE 的端口 |
ENV 环境变量 变量值 | 设置一个环境变量的值,会被后面的RUN使用 |
ADD 源文件/目录 目标文件/目录 | 将源文件复制到目标文件,源文件要与Dockerfile位于相同目录中, 或者是一个URL |
COPY 源文件/目录 目标文件/目录 | 将本地主机上的文件/目录复制到目标地点,源文件/目录要与Dockerfile在相同的目录中 |
VOLUME [“目录”] | 在容器中创建一个挂载点 |
USER 用户名/UID | 指定运行容器时的用户 |
WORKDIR 路径 | 为后续的RUN、CMD、ENTRYPOINT指定 镜像工作目录路径 |
ONBUILD 命令 | 指定所生成的镜像作为一个基础镜像时所要运行的命令(是一个特殊的触发指令) |
HEALTHCHECK | 健康检查 |
SHELL | SHELL 指令可以指定 RUN ENTRYPOINT CMD 指令的 shell,Linux 中默认为 ["/bin/sh", "-c"] |
FROM 指定基础镜像
如:FROM nginx
,就以nginx为基础构建.
Docker 还存在一个特殊的镜像,名为
scratch
。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。FROM scratch
.如果你以
scratch
为基础镜像的话,意味着你不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在。
MAINTAINER 指定维护者的信息
例子:
MAINTAINER glj<admin@199604.com>
RUN 镜像构建时的执行命令
RUN
指令用于制定docker build
过程中要运行的命令的。由于命令行的强大能力,RUN
指令在定制镜像时是最常用的指令之一。其格式有两种:
shell 格式:
RUN <命令>
,就像直接在命令行中输入的命令一样。刚才写的 Dockerfile 中的 RUN
指令就是这种格式。
例子:
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
exec 格式:
RUN ["可执行文件", "参数1", "参数2"]
,这更像是函数调用中的格式。
例子:
RUN yum -y install vim
ENV 设置环境变量
格式有两种:
ENV <key> <value>
例子:
ENV JAVA_VERSION 1.8.0
ENV <key1>=<value1> <key2>=<value2>...
例子:
ENV JAVA_VERSION=1.8.0 DEBUG=on NAME="GLJ"
这个指令很简单,就是设置环境变量而已
WORKDIR 指定工作目录
格式为 WORKDIR <工作目录路径>
。
例子:
WORKDIR /usr/local
COPY 复制文件
格式:
COPY [--chown=<user>:<group>] <源路径>... <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]
和 RUN
指令一样,也有两种格式,一种类似于命令行,一种类似于函数调用。
COPY
指令将从构建上下文目录中 <源路径>
的文件/目录复制到新的一层的镜像内的 <目标路径>
位置。
例子:
COPY index.html /usr/share/nginx/html/index.htm
ADD 扩展了的复制文件
ADD
指令和 COPY
的格式和性质基本一致。但是在 COPY
基础上增加了一些功能。
比如:如果 <源路径>
为一个 tar
压缩文件的话,压缩格式为 gzip
, bzip2
以及 xz
的情况下,ADD
指令将会自动解压缩这个压缩文件到 <目标路径>
去。
如Centos 官网的Dockerfile就是如此:
FROM scratch
ADD centos-7-x86_64-docker.tar.xz
Docker 官方要求,尽可能的使用
COPY
,因为COPY
的语义很明确另外需要注意的是,
ADD
指令会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。因此在
COPY
和ADD
指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用COPY
指令,仅在需要自动解压缩的场合使用ADD
。
CMD 容器启动需要运行的命令
CMD
指令的格式和 RUN
相似,也是两种格式,推荐使用第二种格式:
shell
格式:CMD <命令>
例子:
CMD echo $JAVA_VERSION
CMD echo "----end----"
exec
格式:CMD ["可执行文件", "参数1", "参数2"...]
例子:
CMD ["/bin/echo", "this is a echo docker"]
CMD
指令指定的程序可被docker run
命令行参数中指定要运行的程序所覆盖。如你指定:
CMD ["/bin/echo", "this is a echo docker"]
build后运行(假设镜像名为mycentos):
docker run mycentos
就会输出: this is a echo docker但是,如;
docker run -it mycentos /bin/bash
,不再输出:this is a echo docker,因为CMD命令被/bin/bash
覆盖了注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。
ENTRYPOINT 容器启动需要运行的命令(入口点)
ENTRYPOINT
的目的和 CMD
一样,都是在指定容器启动程序及参数。
可以搭配 CMD
命令使用:一般是变参才会使用CMD
,这里的 CMD
等于是在给ENTRYPOINT
传参,换句话说实际执行时,将变为:
<ENTRYPOINT> "<CMD>"
CMD
+ENTRYPOINT
的实例:
假设我们需要一个得知自己当前公网 IP 的镜像,那么可以先用 CMD
来实现:
FROM centos:7.9.2009
MAINTAINER glj<admin@199604.com>
ENV TARPATH /home
WORKDIR $TARPATH
RUN yum -y install curl
CMD [ "curl", "-s", "http://myip.ipip.net" ]
假如我们使用 docker build -t checkip:v1 .
来构建镜像的话,如果我们需要查询当前公网 IP.
只需要执行:
[root@gzbsc001 mycentos]# docker run -it checkip:v1
当前 IP:120.235.165.226 来自于:中国 广东 广州 移动
如果需要追加参数怎么办?那么只能CMD
+ENTRYPOINT
配合即可:
FROM centos:7.9.2009
MAINTAINER glj<admin@199604.com>
ENV TARPATH /home
WORKDIR $TARPATH
RUN yum -y install curl
CMD [ "-i" ]
ENTRYPOINT [ "curl", "-s", "http://myip.ipip.net" ]
我们使用 docker build -t checkip:v2 .
来构建镜像.这次我们再来执行:
[root@gzbsc001 mycentos]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
checkip v2 9c528482c01a 7 seconds ago 348MB
checkip v1 b95f6f873e5c 7 minutes ago 348MB
nginx latest 04661cdce581 7 days ago 141MB
tomcat 9.0 43e421a14aec 3 weeks ago 680MB
mysql 5.7 938b57d64674 4 weeks ago 448MB
centos 7.9.2009 eeb6ee3f44bd 2 months ago 204MB
portainer/portainer latest 580c0e4e98b0 8 months ago 79.1MB
java 8 d23bdf5b1b1b 4 years ago 643MB
[root@gzbsc001 mycentos]#
[root@gzbsc001 mycentos]#
[root@gzbsc001 mycentos]# docker run checkip:v2
HTTP/1.1 200 OK
Date: Wed, 17 Nov 2021 09:11:51 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 70
Connection: keep-alive
X-Shadow-Status: 200
X-Via-JSL: 1cf16e4,4f293cc,-
Set-Cookie: __jsluid_h=2144db3d81319385679383be3efd7fcd; max-age=31536000; path=/; HttpOnly
X-Cache: bypass
当前 IP:120.235.165.226 来自于:中国 广东 广州 移动
最最最简单的CMD+ENTRYPOINT 实例:
FROM centos
CMD ["p in cmd"]
ENTRYPOINT ["echo"]
注意:如果 Dockerfile 中如果存在多个
ENTRYPOINT
指令,仅最后一个生效。
VOLUME 定义匿名卷
格式为:
VOLUME ["<路径1>", "<路径2>"...]
例子:VOLUME [''/data1","/data2"]
VOLUME <路径>
例子:VOLUME /data1
在docker运行时,docker会创建一个匿名的volume,并将此volume绑定到容器的data1
目录中,如果容器的/data1
目录下已经有内容,则会将内容拷贝的volume中。也就是,Dockerfile中的VOLUME /data1
与docker run -v /data1 checkip
的匿名挂载效果一样。
在启动容器
docker run
的时候,我们也可以通过 -v 参数修改挂载点。
EXPOSE 暴露端口
仅仅只是声明端口。
格式为 EXPOSE <端口1> [<端口2>...]
。
在 Dockerfile 中写入这样的声明有两个好处,一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;另一个用处则是在运行时使用随机端口映射时,也就是
docker run -P
时,会自动随机映射EXPOSE
的端口。
USER 指定当前用户
用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。
格式:USER <用户名>[:<用户组>]
例子:
RUN groupadd -r redis && useradd -r -g redis redis
USER redis
RUN [ "redis-server" ]
HEALTHCHECK 健康检查
HEALTHCHECK
指令是告诉 Docker 应该如何进行判断容器的状态是否正常,这是 Docker 1.12 引入的新指令。
格式:
HEALTHCHECK [选项] CMD <命令>
:设置检查容器健康状况的命令
HEALTHCHECK
支持下列选项:
--interval=<间隔>
:两次健康检查的间隔,默认为 30 秒;--timeout=<时长>
:健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认 30 秒;--retries=<次数>
:当连续失败指定次数后,则将容器状态视为unhealthy
,默认 3 次。
HEALTHCHECK NONE
:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令
HEALTHCHECK --interval=60s --timeout=40s --retries=5
HEALTHCHECK
和CMD
,ENTRYPOINT
一样,HEALTHCHECK
只可以出现一次,如果写了多个,只有最后一个生效。
SHELL 指令
格式:SHELL ["executable", "parameters"]
SHELL 指令可以指定 RUN
ENTRYPOINT
CMD
指令的 shell,Linux 中默认为 ["/bin/sh", "-c"]
例子:
SHELL ["/bin/sh", "-cex"]
# /bin/sh -cex "nginx"
ENTRYPOINT nginx
SHELL ["/bin/sh", "-cex"]
# /bin/sh -cex "nginx"
CMD nginx
参考Dockerfie
官方文档:https://docs.docker.com/engine/reference/builder
可到Dockerfile
最佳实践文档:https://docs.docker.com/develop/develop-images/dockerfile_best-practices/ 练手实践...
发布自己的镜像到仓库中
DockerHub
1.登录docker login
[root@gzbsc001 mytomcat]# docker login --help
Usage: docker login [OPTIONS] [SERVER]
Log in to a Docker registry.
If no server is specified, the default is defined by the daemon.
Options:
-p, --password string Password
--password-stdin Take the password from stdin
-u, --username string Username
[root@gzbsc001 mytomcat]# docker login -u glj17
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
2.提交镜像
docker push
:将本地的镜像上传到镜像仓库,要先登陆到镜像仓库
推送镜像的规范是: docker push 注册用户名/镜像名:[tag]
tag命令修改为规范的镜像:
docker tag dec02f4c1226 glj17/mynginx:1.21.4
[root@gzbsc001 mytomcat]# docker tag dec02f4c1226 glj17/mynginx:1.21.4
[root@gzbsc001 mytomcat]# docker push glj17/mynginx:1.21.4
The push refers to repository [docker.io/glj17/mynginx]
eac18618a1e0: Pushed
3f9029f7aeb1: Pushed
36fdbc2fc6f3: Pushed
663de1ca3bab: Pushed
40c95c921670: Pushed
b4e84b4eb3f3: Pushed
394d004881a3: Pushed
174f56854903: Mounted from library/centos
1.21.4: digest: sha256:fc510ef8eb9483255386f2da07e4ddba04630ed2de85d9c8a39d4e0556b8b5b8 size: 1992
Dockerfile实战
构建sshd镜像
[root@gzbsc001 tmp]# mkdir mysshd
[root@gzbsc001 tmp]# cd mysshd/
[root@gzbsc001 mysshd]# vim Dockerfile # 编写dockerfile文件
FROM centos:7.9.2009
MAINTAINER this is mysshd glj<admin@199604.com>
RUN yum -y update
RUN yum -y install openssh* net-tools lsof telnet passwd
RUN echo '123456!@#' | passwd --stdin root
RUN sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config
RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
RUN sed -i '/^session\s\+required\s\+pam_loginuid.so/s/^/#/' /etc/pam.d/sshd
RUN mkdir -p /root/.ssh && chown root:root /root && chmod 700 /root/.ssh
EXPOSE 22
CMD ["/usr/sbin/sshd" , "-D"]
[root@gzbsc001 mysshd]# docker build -t mysshd:v1 .
[root@gzbsc001 mysshd]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mysshd v1 677eca2f9c45 34 seconds ago 719MB
[root@gzbsc001 mysshd]# docker run -d -P mysshd:v1
724dcf29adba83c32add89b3f42a4287006900ec0540b52061eaa24fddcc1e75
[root@gzbsc001 mysshd]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
724dcf29adba mysshd:v1 "/usr/sbin/sshd -D" 24 seconds ago Up 24 seconds 0.0.0.0:49156->22/tcp, :::49156->22/tcp priceless_elbakyan
[root@gzbsc001 mysshd]# ssh 127.0.0.1 -p49156
The authenticity of host '[127.0.0.1]:49156 ([127.0.0.1]:49156)' can't be established.
RSA key fingerprint is SHA256:WfwbFngOT9C5dDkPhMTFUNZnuLiSuhf2qZI7hZlOU+M.
RSA key fingerprint is MD5:e5:17:10:32:8b:cb:8a:17:ca:18:2a:6a:93:4f:22:ad.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[127.0.0.1]:49156' (RSA) to the list of known hosts.
root@127.0.0.1's password:
[root@724dcf29adba ~]# pwd
/root
构建Nginx镜像
[root@gzbsc001 tmp]# mkdir mynginx
[root@gzbsc001 tmp]# cd mynginx/
[root@gzbsc001 mynginx]# vim Dockerfile # 编写dockerfile文件
FROM centos:7.9.2009
MAINTAINER this is mynginx glj<admin@199604.com>
RUN yum install -y proc-devel gcc gcc-c++ zlib zlib-devel make openssl-devel wget
ADD nginx-1.21.4.tar.gz /usr/local/
WORKDIR /usr/local/nginx-1.21.4/
RUN ./configure --prefix=/usr/local/nginx && make && make install
EXPOSE 80
EXPOSE 443
RUN echo "daemon off;">>/usr/local/nginx/conf/nginx.conf
WORKDIR /root/nginx
COPY run.sh /run.sh
RUN chmod 755 /run.sh
CMD ["/run.sh"]
[root@gzbsc001 mynginx]# vim run.sh
#!/bin/bash
/usr/local/nginx/sbin/nginx ##开启Nginx服务
[root@gzbsc001 mynginx]# wget http://nginx.org/download/nginx-1.21.4.tar.gz #下载nginx包
[root@gzbsc001 mynginx]# docker build -t mynginx:1.21.4 . ##创建镜像
Successfully built dec02f4c1226
Successfully tagged mynginx:1.21.4
[root@gzbsc001 mynginx]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mynginx 1.21.4 dec02f4c1226 12 minutes ago 475MB
[root@gzbsc001 mynginx]# docker run -d -P mynginx:1.21.4
b84a7cb5893729971b4685edec75300a98e640b60853f4443db4acb37181228c
[root@gzbsc001 mynginx]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b84a7cb58937 mynginx:1.21.4 "/run.sh" 5 seconds ago Up 4 seconds 0.0.0.0:49158->80/tcp, :::49158->80/tcp, 0.0.0.0:49157->443/tcp, :::49157->443/tcp gallant_matsumoto
构建Tomcat镜像
[root@gzbsc001 tmp]# mkdir mytomcat
[root@gzbsc001 tmp]# cd mytomcat/
[root@gzbsc001 mytomcat]# vim Dockerfile # 编写dockerfile文件
FROM centos:7.9.2009
MAINTAINER this is mytomcat glj<admin@199604.com>
ADD jdk-8u301-linux-x64.tar.gz /usr/local
WORKDIR /usr/local
RUN mv jdk1.8.0_301 /usr/local/java
ENV JAVA_HOME /usr/local/java ##设置环境变量
ENV JAVA_BIN /usr/local/java/bin
ENV JRE_HOME /usr/local/java/jre
ENV PATH $PATH:/usr/local/java/bin:/usr/local/java/jre/bin
ENV CLASSPATH /usr/local/java/jre/bin:/usr/local/java/lib:/usr/local/java/jre/lib/charsets.jar
ADD apache-tomcat-8.5.72.tar.gz /usr/local
WORKDIR /usr/local
RUN mv apache-tomcat-8.5.72 /usr/local/tomcat8
EXPOSE 8080
ENTRYPOINT ["/usr/local/tomcat8/bin/catalina.sh","run"]
#自行上传或者wget下载对应的包
[root@gzbsc001 mytomcat]# wget https://d6.injdk.cn/oraclejdk/8/jdk-8u301-linux-x64.tar.gz
[root@gzbsc001 mytomcat]# wget dlcdn.apache.org/tomcat/tomcat-8/v8.5.72/bin/apache-tomcat-8.5.72.tar.gz
[root@gzbsc001 mytomcat]# docker build -t mytomcat:8.5.72 . ##创建镜像
Successfully built 25102a5b9a73
Successfully tagged mytomcat:8.5.72
[root@gzbsc001 mytomcat]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mytomcat 8.5.72 25102a5b9a73 38 seconds ago 956MB
[root@gzbsc001 mytomcat]# docker run -P -it mytomcat:8.5.72 /bin/bash
[root@gzbsc001 mynginx]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7ec02971fd62 mytomcat:8.5.72 "/usr/local/tomcat8/…" 18 seconds ago Up 17 seconds 0.0.0.0:49159->8080/tcp, :::49159->8080/tcp reverent_franklin