Dockerfile
# Dockerfile简介
Dockerfile
是将我们的docker
镜像,使用自动化的方式实现出来。
注意:Dockerfile
在使用的时候,首字母必须大写。
主要内容
基础镜像信息 从哪来?
维护者信息 我是谁?
镜像操作指令 怎么干?
容器启动时执行指令 嗨! ! !
1
2
3
4
2
3
4
命令语法
构建镜像命令格式:
docker build -t [镜像名]:[版本号] [Dockerfile所在目录]
构建样例:
docker build -t nginx:v0.2 /opt/dockerfile/nginx/
参数详解:
-t 指定构建后的镜像信息,默认是以构建后的docker image的id号为镜像名称
/opt/dockerfile/nginx/代表Dockerfile存放位置,如果是当前目录,则用﹒(点)表示
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 简单实践
准备工作
# 创建Dockerfile专用目录
root@docker:~# mkdir /data/docker/base/ -p
root@docker:~# cd /data/docker/base/
# 准备文件
root@docker:/data/docker/base# cp ~/.pip/pip.conf ./
root@docker:/data/docker/base# ls
pip.conf
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
定制Dockerfile
root@docker:/data/docker/base# cat Dockerfile
# 构建一个基于python3的定制镜像
# 基础镜像
FROM ubuntu
# 作者信息
MAINTAINER bi
# 执行操作
RUN apt-get update
RUN apt-get install python3 -y && apt-get install python3-pip -y
WORKDIR /root/.pip/
ADD ./pip.conf ./pip.conf
WORKDIR /
# 入口指令
ENTRYPOINT ["/bin/bash"]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
构建镜像
# 构建镜像
root@docker:/data/docker/base# docker build -t python3:v0.1 .
# 使用新镜像启动一个容器,查看效果
root@docker:/data/docker/base# docker run -itd --name python python3:v0.1
# 容器检查
root@docker:/data/docker/base# docker ps
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 构建指令
# 基础指令
FROM
语法:
FROM <image>
FROM <image>:<tag>
解释:
FROM是Dockerfile里的第一条而且只能是除了首行注释之外的第一条指令
1
2
3
4
5
2
3
4
5
MAINTAINER
语法:
MAINTAINER <name>
解释:
指定该dockerfile文件的维护者信息。
类似在docker commit时候使用-a参数指定的信息
1
2
3
4
5
2
3
4
5
RUN
语法:
RUN <command> (shell模式)
RUN ["executable","paraml","param2"] (exec模式)
解释:
表示当前镜像构建时候运行的命令
1
2
3
4
5
2
3
4
5
执行模式∶
模式 | 格式 | 示例 |
---|---|---|
shell模式 | 类似于/bin/bash -c command | RUN echo hello |
exec模式 | 类似于RUN["/bin/bash", "-c", "command"] | RUN ["echo", "hello"] |
EXPOSE
语法:
EXPOSE <port> [<port>...]
解释:
设置Docker容器对外暴露的端口号,Docker为了安全,不会自动对外打开端口,如果需要外部提供访问,还需要启动容器时增加-p或者-P参数对容器的端口进行分配。
1
2
3
4
2
3
4
ENTRYPOINT
语法:
ENTRYPOINT ["executable","paraml","param2"] (exec模式)
ENTRYPOINT command paraml param2 (shell模式)
解释:
每个Dockerfile中只能有一个ENTRYPOINT,当指定多个时,只有最后一个起效。
1
2
3
4
5
2
3
4
5
# 其他指令
ADD
语法:
ADD <src>... <dest>
ADD ["<src>" ,... "<dest>"]
解释:
将指定的文件复制到容器文件系统中的
src指的是宿主机,dest指的是容器
如果源文件是个压缩文件,则docker会自动帮解压到指定的容器中(无论目标是文件还是目录,都会当成目录处理)。
1
2
3
4
5
6
7
2
3
4
5
6
7
COPY
语法:
COPY <src>... <dest>
COPY ["<src>" ,... "<dest>"]
解释:
单纯复制文件场景,Docker推荐使用COPY
1
2
3
4
5
2
3
4
5
VOLUME
语法:
VOLUME ["/data"]
解释:
VOLUME指令可以在镜像中创建挂载点,这样只要通过该镜像创建的容器都有了挂载点
通过VOLUME指令创建的挂载点,无法指定主机上对应的目录,是自动生成的。
1
2
3
4
5
2
3
4
5
ENV
语法:
ENV <key> <value>
ENV <key>=<value> ...
解释:
设置环境变量,可以在RUN之前使用,然后RUN命令时调用,容器启动时这些环境变量都会被指定。
1
2
3
4
5
2
3
4
5
WORKDIR
语法:
WORKDIR /path/to/workdir (shell模式)
解释:
切换目录,为后续的RUN、CMD、ENTRYPOINT指令配置工作目录。相当于cd
1
2
3
4
2
3
4
# 构建解析
# 构建过程
- 从基础镜像1创建一个容器A
- 遇到一条
Dockerfile
指令,都对容器A做一次修改操作 - 执行完一条指令,提交生成一个新镜像2
- 再基于新的镜像2运行一个容器B
- 遇到一条
Dockerfile
指令,都对容器B做一次修改操作 - 执行完一条指令,提交生成一个新镜像3
- ...
# 构建历史
- 构建过程中,创建了很多镜像,这些中间镜像,我们可以直接使用来启动容器,通过查看容器效果,从侧面能看到我们每次构建的效果。
- 提供了镜像调试的能力
- 我们可以通过
docker history <镜像名>
来查看整个构建过程所产生的镜像
# 镜像原理
对于Docker镜像文件整体来说,它是一个只读的文件,但是根据我们对构建过程的理解,我们发现,对于Docker镜像还有很多更深层的东西:
- 镜像文件是基于分层机制实现的
- 最底层是
bootfs
用于启动容器之前系统引导的文件系统,容器启动完毕后,卸载该部分内容以 便节省资源 - 其他层是
rootfs
,有内核挂载为只读模式,而后通过"联合挂载"在其基础上挂载一个"可写层"
- 最底层是
- 下层镜像是上层镜像的父镜像,最底层的称为基础镜像
- 最上层的是可写的,其他各层都是只读的
# 构建缓存
第一次构建很慢,之后的构建都会很快,因为它们用到了构建的镜像缓存。
不使用构建缓存方法:
全部不用缓存:
docker build --no-cache -t [镜像名]:[镜像版本] [Dockerfile位置]
部分不用缓存:
更改Dockerfile的部分代码即可
1
2
3
4
2
3
4
# 使用原则
在工作中,经常会因为业务需求,而定制各种各样的Doker
镜像,由于Dockerfile
的便捷性,所以经常会基于Dockerfile
来创建我们业务场景中所需要的各种镜像。
根据我自己的工作经验,在使用Dockerfile
的过程中,一般只需要关注三个方面即可:
Dockerfile
在使用的过程中,构建的指令越少越好,能合并的就合并。- 基于
Docker
镜像的分层特性,我们最好按照项目的架构级别来定制不同层的镜像 Dockerfiel
构建的过程中,功能越简单越好,最好只有一个
# 基础镜像构建
# ssh基础镜像
定制一个标准的ssh基础镜像,用于我们远程连接或者进行其他的应用镜像的基础镜像
简单实践
# 创建Dockerfile专用目录
root@docker:~# mkdir /docker/images/ssh -p
root@docker:~# cd /docker/images/ssh
# 创建秘钥认证
root@docker:/docker/images/ssh# ssh-keygen -t rsa
root@docker:/docker/images/ssh# cat ~/.ssh/id_rsa.pub > authorized_keys
# 定制Dockerfile
root@docker:/docker/images/ssh# cat Dockerfile
#构建一个基于ubuntu的ssh定制镜像
#基础镜像
FROM ubuntu
#镜像作者
MAINTAINER bi
#安装ssh服务
RUN apt-get update && apt-get install -y openssh-server curl vim net-tools && mkdir -p /var/run/sshd && mkdir -p /root/.ssh && sed -i "s/.*pam_loginuid.so/#&/" /etc/pam.d/sshd && apt-get autoclean && apt-get clean && apt-get autoremove
#复制配置文件到相应位置,并赋予脚本可执行权限
ADD authorized_keys /root/.ssh/authorized_keys
#对外端口
EXPOSE 22
# 启动ssh
CMD ["/usr/sbin/sshd" , "-D"]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
测试效果
# 构建镜像
root@docker:/docker/images/ssh# docker build -t ubuntu-ssh .
# 使用新镜像启动一个容器,查看效果
root@docker:/docker/images/ssh# docker run -d -p 10086:22 ubuntu-ssh
# 容器检查
root@docker:/docker/images/ssh# docker ps
root@docker:/docker/images/ssh# docker port ed90eebaa81c
# ssh查看效果
root@docker:/docker/images/ssh# ssh 10.0.0.21 -p 10086
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# java镜像
定制标准的java
环境,以便于基于java
环境的业务环境使用
简单实践
# 创建Dockerfile专用目录
root@docker:~# mkdir /docker/images/java -p
root@docker:~# cd /docker/images/java
# 定制Dockerfile
root@docker:/docker/images/java# cat Dockerfile
# 构建一个基于ubuntu-ssh定制java镜像
# 基础镜像
FROM ubuntu-ssh
# 镜像作者
MAINTAINER bi
# 添加文件到容器
ADD jdk-8u121-linux-x64.tar.gz /data/server/
RUN ln -s /data/server/jdk1.8.0_121 /data/server/java
# 定制环境变量
ENV JAVA_HOME /data/server/java
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH $JAVA_HOME/lib/:$JRE_HOME/lib/
ENV PATH $PATH:$JAVA_HOME/bin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
测试效果
# 构建镜像
root@docker:/docker/images/java# docker build -t ubuntu-jdk:8u121 .
# 使用新镜像启动一个容器,查看效果
root@docker:/docker/images/java# docker run -it --rm ubuntu-jdk:8u121 bash
# 在容器内检查
root@6b30a3b762fd:/# java -version
root@6b30a3b762fd:/# echo $JAVA_HOME
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 应用镜像构建
# tomcat镜像
基于java
环境镜像定制tomcat
镜像
简单实践
# 创建Dockerfile专用目录
root@docker:~# mkdir /docker/images/tomcat -p
root@docker:~# cd /docker/images/tomcat
# 获取应用文件
root@docker:/docker/images/tomcat# wget https://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-10/v10.0.20/bin/apache-tomcat-10.0.20.tar.gz
# 定制Dockerfile
root@docker:/docker/images/tomcat# cat Dockerfile
# 构建一个基于ubuntu-jdk定制tomcat镜像
# 基础镜像
FROM ubuntu-jdk:8u121
# 镜像作者
MAINTAINER bi
# 定制环境变量
ENV TZ "Asia/Shanghai"
ENV LANG en_US.UTF-8
ENV TERM xterm
ENV TOMCAT_MAJOR_VERSION 10
ENV TOMCAT_MINOR_VERSION 10.0.20
ENV CATALINA_HOME /apps/tomcat
ENV APP_DIR ${CATALINA_HOME}/webapps
# 添加文件到容器
ADD apache-tomcat-10.0.20.tar.gz /apps
RUN ln -s /apps/apache-tomcat-10.0.20 /apps/tomcat
# 定制容器的启动命令
CMD ["/bin/bash"]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
测试效果
# 构建镜像
root@docker:/docker/images/tomcat# docker build -t ubuntu-tomcat:v10.0.20 .
# 使用新镜像启动一个容器,查看效果
docker run -it --rm -p 8080:8080 ubuntu-tomcat:v10.0.20 bash
注意:
因为在构建镜像的时候,已经启动了命令bash,所以可以直接进入进去
# 容器检查
root@a23396901623:/# /apps/tomcat/bin/catalina.sh start
root@a23396901623:/# netstat -tnulp
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 应用镜像
基于基础的tomcat
镜像,运行两个专用的tomcat
项目
简单实践
# 创建Dockerfile专用目录
root@docker:~# mkdir /docker/web/tomcat/tomcat-app{1,2} -p
root@docker:~# cd /docker/web/tomcat
# 定制tomcat-app1
root@docker:/docker/web/tomcat# cd /docker/images/tomcat/
root@docker:/docker/images/tomcat# tar xf apache-tomcat-10.0.20.tar.gz
root@docker:/docker/images/tomcat# cp apache-tomcat-10.0.20/conf/server.xml /docker/web/tomcat/tomcat-app1
# 修改 tomcat-app1/server.xml 配置文件
root@docker:/docker/images/tomcat# cd /docker/web/tomcat/tomcat-app1
# 开放8009端口
<Connector protocol="AJP/1.3"
address="::1"
port="8009"
redirectPort="8443" />
# 定制应用目录
<Host name="localhost" appBase="/data/server/tomcat/webapps"
unpackWARs="true" autoDeploy="true">
# 定制tomcat-app1的应用首页
root@docker:/docker/web/tomcat/tomcat-app1# mkdir ROOT
root@docker:/docker/web/tomcat/tomcat-app1# echo "welcome to Tomcat-app1" > ROOT/index.jsp
root@docker:/docker/web/tomcat/tomcat-app1# tar zcf ROOT.tar.gz ROOT
# 定制tomcat服务启动脚本
root@docker:/docker/web/tomcat/tomcat-app1# cat tomcat_service.sh
# !/bin/bash
# 定制容器里面的tomcat服务启动脚本
# 定制dns解析文件
echo "nameserver 10.0.0.2"> /etc/resolv.conf
# 定制服务启动命令
/apps/tomcat/bin/catalina.sh start
# 定制信息的输出
tail -f /etc/hosts
# 定制Dockerfile
root@docker:/docker/web/tomcat/tomcat-app1# cat Dockerfile
# 构建一个基于ubuntu-tomcat定制tomcat app镜像
# 基础镜像
FROM ubuntu-tomcat:v10.0.20
# 镜像作者
MAINTAINER bi
# 增加相关文件
ADD server.xml /apps/tomcat/conf/server.xml
ADD tomcat_service.sh /apps/tomcat/bin/tomcat_service.sh
ADD ROOT.tar.gz /data/server/tomcat/webapps/
# 开放tomcat服务端口
EXPOSE 8080 8009
# 定制容器的启动命令
CMD ["/bin/bash","/apps/tomcat/bin/tomcat_service.sh"]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
测试效果
# 构建镜像
root@docker:/docker/web/tomcat/tomcat-app1# docker build -t tomcat-web:app1 .
# 使用新镜像启动一个容器,查看效果
root@docker:/docker/web/tomcat/tomcat-app1# docker run -d -p 8080:8080 tomcat-web:app1
# 容器检查
root@docker:/docker/web/tomcat/tomcat-app1# docker port 5e72ea0547f8
root@docker:/docker/web/tomcat/tomcat-app1# curl 127.0.0.1:8080
welcome to Tomcat-app1
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
同样的方式定制第二个tomcat web镜像
# 准备文件
root@docker:/docker/web/tomcat/tomcat-app1# cd /docker/web/tomcat
root@docker:/docker/web/tomcat# cp -a tomcat-app1/* tomcat-app2/
root@docker:/docker/web/tomcat# cd tomcat-app2/
root@docker:/docker/web/tomcat/tomcat-app2# sed -i 's#app1#app2#' ROOT/index.jsp
root@docker:/docker/web/tomcat/tomcat-app2# rm -rf ROOT.tar.gz
root@docker:/docker/web/tomcat/tomcat-app2# tar zcf ROOT.tar.gz ROOT
# 构建镜像
root@docker:/docker/web/tomcat/tomcat-app2# docker build -t tomcat-web:app2 .
# 测试效果
root@docker:/docker/web/tomcat/tomcat-app2# docker run -d -p 8081:8080 tomcat-web:app2
root@docker:/docker/web/tomcat/tomcat-app2# curl 127.0.0.1:8081
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
Last Updated: 2022/04/06, 22:48:37