Dockerfile

时间:2021-03-16 01:14:35


Dockerfile

  • Dockerfile简介
  • 1-Dockerfile基本介绍
  • 2-Dockerfile构建过程
  • 3-Dockerfile指令用法
  • Dockerfile构建镜像
  • 1-Dockerfile使用CentOS构建apache镜像
  • 1-1相应Dockerfile目录
  • 1-2Dockerfile文件内容
  • 1-3entrypoint.sh脚本文件内容
  • 1-4创建镜像
  • 1-5基于镜像创建容器进行测试
  • 2-Dockerfile使用alpine创建apache镜像
  • 2-1Dockerfile相应目录
  • 2-2 Dockerfile文件内容
  • 2-3entrypoint.sh文件内容
  • 2-4创建镜像
  • 2-5基于镜像创建容器测试
  • Dockerfile上传镜像
  • 1-CentOS镜像上传
  • 1-1登录Docker.io
  • 1-2上传Docker.io
  • 2-alpine镜像上传
  • 2-1登录到Docker.io
  • 2-2上传到Docker.io

Dockerfile简介

1-Dockerfile基本介绍

基本结构
Dockerfile 是一个文本格式的配置文件,用户可以使用 Dockerfile 快速创建自定义镜像。

Dockerfile 由一行行命令语句组成,并且支持以 # 开头的注释行。

Docker分为四部分:

  • 基础镜像信息
  • 维护者信息
  • 镜像操作指令
  • 容器启动时默认要执行的指令
    例如:
# This dockerfile uses the ubuntu image
# VERSION 2 - EDITION 1
# Author: GIN
# Command format: Instruction [arguments / command] ...

# 第一行必须指定基于的基础镜像
FROM ubuntu

# 维护者信息
LABEL MAINTAINER='GIN 163@163.com'

# 镜像操作指令
RUN apt-get update && apt-get install -y nginx
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf

# 容器启动时默认要执行的指令
CMD /usr/sbin/nginx
其中,一开始必须指明所基于的镜像名称,接下来一般会说明维护者信息。
后面则是镜像操作指令,例如RUN指令,RUN指令将对镜像执行跟随的命令。每运行一条RUN指令,镜像添加新的一层,并提交。
最后是CMD指令来指定运行容器时的操作指令。

2-Dockerfile构建过程

基础:

每条保留字指令必须为大写字母,且后面至少要跟随一个参数
指令按照从上到下,顺序执行
#表示注释
每条指令都会创建一个新的镜像层,并对镜像进行提交
应用软件的角度看,DockerFile、Docker镜像与Docker容器分别代表软件的三个不同阶段:

  • DockerFile是软件的原材料
  • Docker镜像是软件的交付品
  • Docker容器则可以认为是软件的运行态。
  • DockerFile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石。

Dockerfile

详细解释:

  • DockerFile,需要定义一个DockerFile,DockerFile定义了进程需要的一切东西。DockerFile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这是需要考虑如何涉及namespace的权限控制)等到。
  • Docker镜像,在用DockerFile定义一个文件后,docker build会产生一个- Docker镜像,当运行Docker镜像时,会真正开始提供服务。
  • Docker容器,容器直接提供服务。

3-Dockerfile指令用法

指令
指令的一般格式为INSTRUCTION arguments,指令包括:

FROM			#基础镜像,当前镜像是基于哪个镜像的
MAINTAINER		#镜像作者 姓名+邮箱
RUN				#容器构建是需要运行的命令(构建镜像中执行一些命令,如Redis的DockerFile中的run命令建立用户组)
ADD				#将宿主机目录下的文件拷贝进镜像,且 ADD命令会自动处理URL和解压tar文件
COPY			#类似ADD,拷贝文件和目录到镜像中。将从构建上下文目录<源路径>的文件/目录复制到新的一层的镜像内<目标路径>位置。
VOLUME			#容器数据卷,用于数据保存和持久化工作
CMD				#指定容器启动时要运行的命令。DockerFile中可以有多个CMD指令,但只有最后一个生效(覆盖),CMD会被docker run 之后的参数替换
ENTRYPOINT  	#指定容器启动时要运行的命令。ENTRYPOINT的目的和CMD一样,都是在指定容器启动程序以及参数(但是不会被覆盖)
EXPOSE			#当前容器对外暴露的端口
WORKDIR     	#指定在创建容器后,终端默认登录(启动后的工作目录)进来的工作目录,一个落脚点
ENV				#用来在构建镜像过程中设置环境变量
ONBUILD     	#当构建一个被集成的DockerFile时运行命令,父镜像在被子集成后父镜像的ONBUILD被触发

格式为FROM 或FROM :。

第一条指令必须为FROM指令。并且,如果在同一个Dockerfile中创建多个镜像时,可以使用多个FROM指令(每个镜像一次)。

LABEL MAINTAINER
格式为LABEL MAINTAINER ,指定维护者信息

RUN
格式为RUN 或RUN [“executable”,“param1”,“param2”]。

前者将在shell终端中运行命令,即/bin/sh -c;后者则使用exec执行。指定使用其他终端可以通过第二种方式实现,例如:

RUN ["/bin/bash","-c","echo hello"]

每条RUN指令将在当前镜像基础上执行指定命令,并提交为新的镜像。当命令较长时可以使用 \ 来换行,例如:

RUN echo "hello world\nhello tom" > /tmp/abc && \
    cat /tmp/abc

CMD
CMD支持三种格式:

CMD ["executable","param1","param2"]使用exec执行,推荐方式
CMD command param1 param2在/bin/sh中执行,提供给需要交互的应用
CMD ["param1","param2"]提供给ENTRYPOINT的默认参数

CMD用于指定启动容器时默认要执行的命令,每个Dockerfile只能有一条CMD命令。如果指定了多条命令,只有最后一条会被执行。

如果用户启动容器时指定了运行的命令,则会覆盖掉CMD指定的命令。

EXPOSE
格式为EXPOSE […]。
例如:

EXPOSE 22 80 8443

EXPOSE用于告诉Docker服务器容器暴露的端口号,供互联系统使用。

在启动容器时通过-P,Docker主机会自动分配一个端口转发到指定的端口;
使用-p则可以具体指定哪个本地端口映射过来。

ENV
格式为ENV 。指定一个环境变量,会被后续RUN指令使用,并在容器运行时保持。例如:

ENV PG_MAJOR 9.3
ENV PG_VERSION 9.3.4
RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && ...
ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH

ADD
格式为ADD 。

该命令将复制指定的到容器中的。其中可以是Dockerfile所在目录的一个相对路径(文件或目录);也可以是一个URL;还可以是一个tar文件(会自动解压为目录)。

COPY
格式为COPY 。

复制本地主机的(为Dockerfile所在目录的相对路径,文件或目录)为容器中的。目标路径不存在时会自动创建。
当使用本地目录为源目录时,推荐使用COPY。

ENTRYPOINT
ENTRYPOINT有两种格式:

ENTRYPOINT ["executable","param1","param2"]
ENTRYPOINT command param1 param2(在shell中执行)

配置容器启动后执行的命令,并且不可被docker run提供的参数覆盖。而且,如果在docker run的后面提供了参数,这些命令行参数会被当作参数传递给ENTRYPOINT指定的程序。

每个Dockerfile中只能有一个ENTRYPOINT,当指定多个ENTRYPOINT时,只有最后一个生效。

VOLUME
格式为VOLUME [“/data”]。

创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等。

USER
格式为USER daemon。

指定运行容器时的用户名或UID,后续的RUN也会使用指定用户。

当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户,例如:

RUN groupadd -r postgres && useradd -r -g postgres postgres

要临时获取管理员权限可以使用gosu,而不推荐sudo。如果不指定,容器默认是root运行。

WORKDIR
格式为WORKDIR /path/to/workdir。

为后续的RUN、CMD、ENTRYPOINT指令配置工作目录。
可以使用多个WORKDIR指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。例如:

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

则最终路径为/a/b/c。

ONBUILD
格式为ONBUILD [INSTRUCTION]。

配置当所创建的镜像作为其他镜像的基础镜像时,所执行的操作指令。

例如,Dockerfile使用如下的内容创建了镜像image-A

[...]
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
[...]

此时,如果基于image-A创建新的镜像时,新的Dockerfile中使用FROM image-A指定基础镜像时,会自动执行ONBUILD指令的内容,等价于在后面添加了两条指令。

FROM image-A

#Automatically run the following
ADD . /app/src
RUN /usr/local/bin/python-build --dir /app/src

使用ONBUILD指令的镜像,推荐在标签中注明,例如ruby:1.9-onbuild。

Dockerfile构建镜像

1-Dockerfile使用CentOS构建apache镜像

1-1相应Dockerfile目录

//目录树
[root@localhost ~]# cd apache/
[root@localhost apache]# tree
.
|-- Dockerfile
|-- packages
|   |-- apr-1.6.5.tar.gz
|   |-- apr-util-1.6.1.tar.gz
|   `-- httpd-2.4.54.tar.bz2
`-- scripts
    `-- entrypoint.sh

2 directories, 5 files

1-2Dockerfile文件内容

//Dockerfile文件内容
[root@localhost apache]# cat Dockerfile 
FROM centos

LABEL MAINTAINER='GIN 1078029320@qq.com'

ENV httpd_version 2.4.54
ENV PATH /usr/local/apache/bin:$PATH

ADD packages/apr-1.6.5.tar.gz packages/apr-util-1.6.1.tar.gz packages/httpd-${httpd_version}.tar.bz2 /usr/src/

RUN rm -f /etc/yum.repos.d/* && \
    curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-$(awk -F'[ .]+' '{print $4}' /etc/redhat-release).repo && \
    sed -i -e '/mirrors.cloud.aliyuncs.com/d' -e '/mirrors.aliyuncs.com/d' /etc/yum.repos.d/CentOS-Base.repo && \
    yum clean all && yum makecache && \
    yum -y install epel-release openssl-devel pcre-devel expat-devel libtool gcc gcc-c++ make libxml2-devel && \
    yum groups mark install 'Development Tools' -y && \
    useradd -r -M -s /sbin/nologin apache && \
    cd /usr/src/apr-1.6.5 && \
    sed -i '/$RM "$cfgfile"/d' configure && \
    ./configure --prefix=/usr/local/apr && make && make install && \
    cd ../apr-util-1.6.1 && \
    ./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr && \
    make && make install && \
    cd ../httpd-$httpd_version && \
    ./configure --prefix=/usr/local/apache \
    --enable-so \
    --enable-ssl \
    --enable-cgi \
    --enable-rewrite \
    --with-zlib \
    --with-pcre \
    --with-apr=/usr/local/apr \
    --with-apr-util=/usr/local/apr-util/ \
    --enable-modules=most \
    --enable-mpms-shared=all \
    --with-mpm=prefork && make -j $(nproc) && make install && \
    sed -i '/#ServerName/s/#//g' /usr/local/apache/conf/httpd.conf && \
    yum -y remove gcc gcc-c++ make && \
    rm -rf /var/cache/* && \
    rm -rf /usr/src/*
    
WORKDIR /usr/local/apache

EXPOSE 80

CMD ["-D","FOREGROUND"]

ENTRYPOINT ["apachectl"]

1-3entrypoint.sh脚本文件内容

//entrypoint.sh 文件内容
[root@localhost apache]# cd scripts/
[root@localhost scripts]# cat entrypoint.sh 
#!/bin/bash

sed -i '/#ServerName/s/#//g' /usr/local/apache/conf/httpd.conf

exec "$@"

1-4创建镜像

[root@localhost apache]# podman build -t httpd:v1.0 .
过程省略......

[root@localhost ~]# podman images
REPOSITORY             TAG         IMAGE ID      CREATED         SIZE
localhost/httpd        v1.0        86e3eb9c59e8  27 minutes ago  417 MB

1-5基于镜像创建容器进行测试

[root@localhost ~]# podman run -P --name web httpd:v1.0 

[root@localhost ~]# podman ps
CONTAINER ID  IMAGE                 COMMAND        CREATED         STATUS             PORTS                  NAMES
5a9f17faee1b  localhost/httpd:v1.0  -D FOREGROUND  39 seconds ago  Up 39 seconds ago  0.0.0.0:45537->80/tcp  web
[root@localhost ~]# podman inspect -l | grep -i 'ipaddr'
               "IPAddress": "10.88.0.8",
                         "IPAddress": "10.88.0.8",
[root@localhost ~]# curl 10.88.0.8
<html><body><h1>It works!</h1></body></html>

2-Dockerfile使用alpine创建apache镜像

2-1Dockerfile相应目录

[root@localhost ~]# cd apache/
[root@localhost apache]# tree
.
|-- Dockerfile
|-- packages
|   |-- apr-1.6.5.tar.gz
|   |-- apr-util-1.6.1.tar.gz
|   `-- httpd-2.4.54.tar.bz2
`-- scripts
    `-- entrypoint.sh

2 directories, 5 files

2-2 Dockerfile文件内容

[root@localhost apache]# cat Dockerfile 
FROM alpine

LABEL MAINTAINER='GIN 1078029320@qq.com'

ENV httpd_version 2.4.54
ENV PATH /usr/local/apache/bin:$PATH

ADD packages/apr-1.6.5.tar.gz packages/apr-util-1.6.1.tar.gz packages/httpd-${httpd_version}.tar.bz2 /tmp/

RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
    apk update && \
    apk add --no-cache -U gcc make libc-dev openssl-dev expat-dev libtool pcre-dev && \
    adduser -H -S -s /sbin/nologin apache && \
    cd /tmp/apr-1.6.5 && \
    sed -i '/$RM "$cfgfile"/d' configure && \
    ./configure --prefix=/usr/local/apr && \
    make && make install && \
    cd ../apr-util-1.6.1 && \
    ./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr && \
    make && make install && \
    cd ../httpd-$httpd_version && \
    ./configure --prefix=/usr/local/apache \
    --enable-so \
    --enable-ssl \
    --enable-cgi \
    --enable-rewrite \
    --with-zlib \
    --with-pcre \
    --with-apr=/usr/local/apr \
    --with-apr-util=/usr/local/apr-util/ \
    --enable-modules=most \
    --enable-mpms-shared=all \
    --with-mpm=prefork && make -j $(nproc) && make install && \
    sed -i '/#ServerName/s/#//g' /usr/local/apache/conf/httpd.conf && \
    apk del gcc  make && \
    rm -rf /tmp/* && \
    rm -rf /var/cache/* 

WORKDIR /usr/local/apache

EXPOSE 80

CMD ["-D","FOREGROUND"]

ENTRYPOINT ["apachectl"]

2-3entrypoint.sh文件内容

[root@localhost apache]# cat scripts/entrypoint.sh 
#!/bin/bash

sed -i '/#ServerName/s/#//g' /usr/local/apache/conf/httpd.conf

exec "$@"

2-4创建镜像

[root@localhost apache]# podman build -t docker.io/knightsl/httpd:v2 .
过程省略......

[root@localhost ~]# podman images
REPOSITORY                TAG         IMAGE ID      CREATED       SIZE
docker.io/knightsl/httpd  v2          9afc4b353604  4 hours ago   119 MB
docker.io/knightsl/httpd  v1.0        86e3eb9c59e8  20 hours ago  417 MB
docker.io/library/alpine  latest      9c6f07244728  3 weeks ago   5.83 MB

2-5基于镜像创建容器测试

[root@localhost ~]# podman run -P --name web docker.io/knightsl/httpd:v2

[root@localhost ~]# podman ps
CONTAINER ID  IMAGE                        COMMAND        CREATED         STATUS             PORTS                  NAMES
50936f8fdba0  docker.io/knightsl/httpd:v2  -D FOREGROUND  16 seconds ago  Up 16 seconds ago  0.0.0.0:35799->80/tcp  w
[root@localhost ~]# podman inspect -l | grep -i 'ipaddr'
               "IPAddress": "10.88.0.5",
                         "IPAddress": "10.88.0.5",
[root@localhost ~]# curl 10.88.0.5
<html><body><h1>It works!</h1></body></html>

Dockerfile上传镜像

1-CentOS镜像上传

1-1登录Docker.io

[root@localhost ~]# podman login docker.io
Username: knightsl
Password: 
Login Succeeded!

1-2上传Docker.io

[root@localhost ~]# podman tag localhost/httpd:v1.0 docker.io/knightsl/httpd:v1.0

[root@localhost ~]# podman push docker.io/knightsl/httpd:v1.0 
Getting image source signatures
Copying blob 7588e09e03fa done  
Copying blob 622b5e0bbb42 done  
Copying blob 2653d992f4ef skipped: already exists  
Copying config 86e3eb9c59 done  
Writing manifest to image destination
Storing signatures

Dockerfile

2-alpine镜像上传

2-1登录到Docker.io

[root@localhost ~]# #podman push docker.io/knightsl/httpd:v2
[root@localhost ~]# podman login docker.io
Username: knightsl
Password: 
Login Succeeded!

2-2上传到Docker.io

[root@localhost ~]# podman push docker.io/knightsl/httpd:v2
Getting image source signatures
Copying blob 860d21139d6e done  
Copying blob c479917bfb4b done  
Copying blob 994393dc58e7 skipped: already exists  
Copying config 9afc4b3536 done  
Writing manifest to image destination
Storing signatures

Dockerfile