使用Dockerfile构建自己的镜像

Dockerfile是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。使用docker build命令可以根据Dockerfile里面的指令编排来打包定制我们自己的docker镜像,首先我们来看一个通用的例子,制作自己的nginx镜像。

1.构建nginx镜像

# Base image
FROM centos:7

# MAINTAINER
MAINTAINER cbmiao <miaocbin@126.com>

# 将nginx以及pcre源代码加入镜像
ADD nginx-1.20.1.tar.gz /usr/local/src/
ADD pcre-8.45.tar.gz /usr/local/src/

# 安装编译器
RUN yum install -y gcc gcc-c++ make openssl-devel lsof
RUN useradd -s /sbin/nologin -M nginx

# 指定工作目录
WORKDIR /usr/local/src/nginx-1.20.1/

# 编译nginx
RUN ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_stub_status_module --with-pcre=/usr/local/src/pcre-8.45 && make && make install
RUN echo "daemon off;" >> /usr/local/nginx/conf/nginx.conf

# 设置环境变量
ENV PATH /usr/local/nginx/sbin:$PATH

# 暴露80端口
EXPOSE 80

# 容器默认启动命令
ENTRYPOINT ["nginx"]

以上是通过Dockerfile来定制我们自己的nginx的Dockerfile,包含了如下指令:

使用Dockerfile构建自己的镜像

2. Dockerfile基本格式

2.1 FROM指令

FROM指令用于指定基础镜像,必须为Dockerfile的第一个指令

格式:
FROM <image>
FROM <image>:<tag>
示例:
FROM mysql:5.7
注意:
tag是可选的,如果不使用tag,则默认会使用latest版本的基础镜像

参数解释:

  • FROM mysql:5.7:第一行必须指定 基础镜像信息

2.2 MAINTAINER 指令

用于说明镜像维护者的信息,名字,邮箱,联系方式,实例如下

格式:
	MAINTAINER <name>
示例:
	MAINTAINER Michael Miu
    MAINTAINER miaocbin@126.com
    MAINTAINER Michael Miu <miaocbin@126.com>

2.3 COPY|ADD指令

这两个命令的用法类似,都可以用于添加本地文件到镜像中,如:

  • 源路径可以有多个,相对于执行build的路径,如果源路径是一个目录,则该目录下面的所有内容都会被加入到容器,但目录本身不会被加入到容器;
  • 目标路径:必须是绝对路径或者相对于WORKDIR的相对路径;若目标路径不存在,则会自动创建完整路径;目标路径如果是文件夹,则必须已/结尾;
  • 路径中可以使用通配符

二者区别如下:

  • COPY指令能够将构建命令所在的主机本地的文件或目录,复制到镜像文件系统。
  • ADD指令不仅能够将构建命令所在的主机本地的文件或目录,而且能够将远程URL所对应的文件或目录,作为资源复制到镜像文件系统。
    所以,可以认为ADD是增强版的COPY,支持将远程URL的资源加入到镜像的文件系统。
格式:
	ADD|COPY <src>... <dest>
示例:
    ADD|COPY tes* /mydir/    # 添加所有以"tes"开头的文件
    ADD|COPY test mydir/     # 添加 "test" 到 WORKDIR/mydir/
    ADD|COPY test /opt/      # 添加 "test" 到 /opt/

说明:

  1. 对于从远程URL获取资源的情况,由于ADD指令不支持认证,如果从远程获取资源需要认证,则只能使用RUN wget或RUN curl替代。
  2. 如果源路径的资源发生变化,则该ADD指令将使Docker Cache失效,Dockerfile中后续的所有指令都不能使用缓存。因此尽量将ADD指令放在Dockerfile的后面。

2.4 WORKDIR

设置工作目录,通过WORKDIR设置工作目录后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY等命令都会在该目录下执行

格式:
	WORKDIR /path/to/workdir
示例:
    WORKDIR /abc  (这时工作目录为/abc)

2.5 RUN

构建镜像过程中执行命令(注意:RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定--no-cache参数,如:docker build --no-cache)

格式:
	RUN <command>
示例:
    RUN yum -y install nginx
    RUN pip install djaong
    RUN mkdir test && rm -rf /var/lib/testfile

2.6 CMD

构建容器后调用,也就是在容器启动时才进行调用。注意:CMD不同于RUN,CMD用于指定在容器启动时所要执行的命令,而RUN用于指定镜像构建时所要执行的命令。

格式:
    CMD ["executable","param1","param2"] (执行可执行文件,优先)
    CMD ["param1","param2"] (设置了ENTRYPOINT,则直接调用ENTRYPOINT添加参数)
    CMD command param1 param2 (执行shell内部命令)
示例:
    CMD ["/usr/bin/wc","--help"]
    CMD ping www.baidu.com

2.7 ENTRYPOINT

设置容器初始化命令,使其可执行化

格式:
    ENTRYPOINT ["executable", "param1", "param2"] (可执行文件, 优先)
    ENTRYPOINT command param1 param2 (shell内部命令)
示例:
    ENTRYPOINT ["/usr/bin/wc","--help"]

注意:ENTRYPOINT与CMD非常类似,不同的是通过docker run执行的命令不会覆盖ENTRYPOINT,而docker run命令中指定的任何参数,都会被当做参数再次传递给ENTRYPOINT。Dockerfile中只允许有一个ENTRYPOINT命令,多指定时会覆盖前面的设置,而只执行最后的ENTRYPOINT指令。

2.8 ENV

格式:
    ENV <key> <value>
    ENV <key>=<value>
示例:
    ENV myName John
    ENV myCat=tomcat

2.9 EXPOSE

EXPOSE并不会让容器的端口访问到主机。要使其可访问,需要在docker run运行容器时通过-p来发布这些端口,或通过-P参数来发布EXPOSE导出的所有端口

格式:
    EXPOSE <port> [<port>...]
示例:
    EXPOSE 80 443
    EXPOSE 8080
    EXPOSE 11211/tcp 11211/udp

3. Dockerfile镜像构建命令

利用Dockerfile构建自己的镜像命令

docker build . -t ImageName:ImageTag -f Dockerfile

3.1 执行构建过程

docker build . -t my-nginx:v1.20.1 -f Dockerfile

Sending build context to Docker daemon  3.163MB
Step 1/13 : FROM centos:7
 ---> 8652b9f0cb4c
Step 2/13 : LABEL maintainer="cbmiao <miaocbin@126.com>"
 ---> Using cache
 ---> 16c2487146bc
Step 3/13 : ENV DEBIAN_FRONTEND noninteractive
 ---> Using cache
 ---> 5f3132177398
Step 4/13 : ADD nginx-1.20.1.tar.gz /usr/local/src/
 ---> Using cache
 ---> 116344a28ea2
Step 5/13 : ADD pcre-8.45.tar.gz /usr/local/src
 ---> Using cache
 ---> 23451b87c29b
Step 6/13 : RUN yum install -y wget gcc gcc-c++ make openssl-devel
 ---> Using cache
 ---> dcaa1cbaf4bd
Step 7/13 : RUN useradd -s /sbin/nologin -M nginx
 ---> Using cache
 ---> e0ace7f20ffc
Step 8/13 : WORKDIR /usr/local/src/nginx-1.20.1/
 ---> Using cache
 ---> d437722febe2
Step 9/13 : RUN ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_stub_status_module --with-pcre=/usr/local/src/pcre-8.45 && make && make install
 ---> Using cache
 ---> 307b6228d110
Step 10/13 : RUN echo "daemon off;" >> /usr/local/nginx/conf/nginx.conf
 ---> Using cache
 ---> dc8e0e800987
Step 11/13 : ENV PATH /usr/local/nginx/sbin:$PATH
 ---> Using cache
 ---> e5a1119dced2
Step 12/13 : EXPOSE 80
 ---> Using cache
 ---> 63c669be20e4
Step 13/13 : ENTRYPOINT ["nginx"]
 ---> Using cache
 ---> 391f75b825bd
Successfully built 391f75b825bd
Successfully tagged my-nginx:v1.20.1

3.2 查看构建结果

docker image ls
REPOSITORY                TAG       IMAGE ID       CREATED          SIZE
my-nginx                  v1.20.1   391f75b825bd   17 minutes ago   490MB

3.3 运行镜像

# 利用我们刚构建的镜像来启动容器
docker run -d --name nginx-test my-nginx:v1.20.1
348a73f420181c36abf7a99c958ed76862503e930793331ab819629ea2bdc4a2

# 进入容器查看nginx状态
docker exec -ti nginx-test bash
[root@348a73f42018 nginx-1.20.1]#

# 确认80端口
[root@348a73f42018 nginx-1.20.1]# lsof -i :80
COMMAND PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nginx     1 root    6u  IPv4 645923      0t0  TCP *:http (LISTEN)
# 确认nginx进程已经启动成功
[root@348a73f42018 nginx-1.20.1]# ps aux
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root          1  0.1  0.0  46096  3280 ?        Ss   05:43   0:00 nginx: master process nginx
nginx         7  0.0  0.0  46532  1880 ?        S    05:43   0:00 nginx: worker process
root          8  0.2  0.0  11828  1908 pts/0    Ss   05:43   0:00 bash
root         26  0.0  0.0  51732  1712 pts/0    R+   05:43   0:00 ps aux
# 访问nginx也正常
[root@348a73f42018 nginx-1.20.1]# curl localhost 
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

若想让我们的nginx向外提供服务,还需要在启动容器时,将端口映射到主机,然后我们通过主机IP加上映射端口,就可以访问了

docker run -d --name nginx-test1 -p 80:80 my-nginx:v1.20.1

以上就添加了一个[-p 80:80]参数,将容器内的nginx的80端口,映射到宿主机。然后我们就可以通过宿主机的IP加上80端口访问刚才启动的nginx容器里的nginx服务,有关docker启动容器有不清楚的,可以看我的另外一篇博客:Docker简介及基本使用

4. Dockerfile构建镜像的原则

  • 不必要的内容不要放在镜像中:以免增大镜像,同时也带来安全隐患;

  • 减少不必要的层文件

  • 减少网络传输操作:尽量使用本地文件,加快镜像构建速度,特别是后面我们将利用Jenkins做自动化构建的时候;

  • 可以适当的包含一些调试命令

5. JAR包制作成docker镜像实例

FROM java:8u211

ENV JAVA_OPTS "-Xmx4096m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m"
ENV JAVA_HOME /usr/local/java
ENV PATH ${PATH}:${JAVA_HOME}/bin

COPY target/myweb.jar myweb.jar

RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo ‘Asia/Shanghai‘ >/etc/timezone

EXPOSE 8080
CMD java ${JAVA_OPTS} -jar myweb.jar

 

使用Dockerfile构建自己的镜像

上一篇:13-网络芯片CH395Q学习开发-模块使用Socket0作为MAC RAW


下一篇:Revit API根据链接文件开洞