Docker 容器 - Dockerfile

Docker 容器 - Dockerfile

  • [一、Dockerfile 基本结构](#一、Dockerfile 基本结构)
  • [二、Dockerfile 指令详解](#二、Dockerfile 指令详解)
    • [2.1 FROM](#2.1 FROM)
    • [2.2 MAINTAINER](#2.2 MAINTAINER)
    • [2.3 COPY](#2.3 COPY)
    • [2.4 ADD](#2.4 ADD)
    • [2.5 WORKDIR](#2.5 WORKDIR)
    • [2.6 VOLUME](#2.6 VOLUME)
    • [2.7 EXPOSE](#2.7 EXPOSE)
    • [2.8 ENV](#2.8 ENV)
    • [2.9 RUN](#2.9 RUN)
    • [2.10 CMD](#2.10 CMD)
    • [2.11 ENTRYPOINT](#2.11 ENTRYPOINT)
  • [三、Dockerfile 创建镜像与模板](#三、Dockerfile 创建镜像与模板)
    • [3.1 Dockerfile 镜像](#3.1 Dockerfile 镜像)
    • [3.2 镜像管理](#3.2 镜像管理)
    • [3.3 Dockerfile 模板](#3.3 Dockerfile 模板)
      • [3.3.1 Redhat 镜像模板](#3.3.1 Redhat 镜像模板)
      • [3.3.2 JDK 镜像模板](#3.3.2 JDK 镜像模板)
      • [3.3.3 Tomcat 镜像模板](#3.3.3 Tomcat 镜像模板)
  • [四、Docker 数据持久化](#四、Docker 数据持久化)
  • 五、案例实战
    • [5.1 构建nginx服务镜像](#5.1 构建nginx服务镜像)

DockerFile 是一个文本格式的配置文件,用户可以使用 DockerFile 来快速创建自定义的镜像

镜像的定制 实际上就是 定制每一层所添加的配置、文件 。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile

一、Dockerfile 基本结构

Dockerfile 分为四部分:基础镜像信息维护者信息镜像操作指令容器启动时执行指令

  • 每条指令创建一层:
    • FROM : 指明所基于的镜像名称
    • MAINTAINER:维护者信息,docker_user 维护(可以不写)。
    • COPY : 从 Docker 客户端的当前目录添加文件,镜像操作 指令。
    • RUN : 构建镜像时 执行 make 命令,每运行一条 RUN 指令,镜像就添加新的一层,并提交(添加可写层)。
    • CMD : 指定在容器中运行什么命令,用来指定运行容器时的操作命令

Docker 镜像由只读层 组成,每个只读层代表一个 Dockerfile 指令。这些层是堆叠的,每个层都是上一层的变化的增量

Docker 可以通过 读取 Dockerfile 指令 来自动构建镜像

powershell 复制代码
# 在一个空目录下,新建一个名为 Dockerfile 文件
mkdir /www/	#/www这个目录是自己创建的,通过创建空目录,在此目录下创建文件
vim /www/Dockerfile

# 编辑 Dockerfile
FROM nginx:1.27.4

# 维护者,可以省略
MAINTAINER kendra kendra@docker.com

# 启动容器
RUN mkdir /usr/share/nginx/html -p
RUN echo "hello docker" > /usr/share/nginx/html/index.html

# 构建镜像 . : 根据当前上下文环境构建
docker build -t mynginx:v1.0 .

# 运行
docker run --rm -it mynginx:v1.0 /bin/bash
shell 复制代码
[root@Docker-kd ]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
tomcat       11.0.5    e8c9a002d37b   7 weeks ago    467MB
nginx        1.27.4    4cad75abc83d   2 months ago   192MB
mysql        8.4.4     4a8a163431d3   3 months ago   769MB
busybox      latest    ff7a7936e930   7 months ago   4.28MB
[root@Docker-kd ]# ls /
afs  boot  etc   lib    media  opt   root  sbin  sys  usr
bin  dev   home  lib64  mnt    proc  run   srv   tmp  var
[root@Docker-kd ]# mkdir /www
[root@Docker-kd ]# cd /www/
[root@Docker-kd www]# ls
[root@Docker-kd www]# vim Dockerfile
[root@Docker-kd www]# cat Dockerfile
FROM nginx:1.27.4
MAINTAINER kendra kendra@docker.com

RUN mkdir /usr/share/nginx/html -p
RUN echo "hello docker" > /usr/share/nginx/html/index.html

编辑界面:w保存,另一个会话即可构建镜像、运行,测试

  • 另起一个会话
    • 构建:docker build -t mynginx:v1.0 .
    • 运行:docker run --rm -it mynginx:v1.0 /bin/bash
shell 复制代码
[root@Docker-kd ~]# cd /www/
[root@Docker-kd www]# ls
Dockerfile
# 构建
[root@Docker-kd www]# docker build -t mynginx:v1.0 .
[+] Building 0.9s (7/7) FINISHED                                           docker:default
 => [internal] load build definition from Dockerfile                                 0.0s
 => => transferring dockerfile: 245B                                                 0.0s
 => WARN: MaintainerDeprecated: Maintainer instruction is deprecated in favor of us  0.0s
 => [internal] load metadata for docker.io/library/nginx:1.27.4                      0.0s
 => [internal] load .dockerignore                                                    0.0s
 => => transferring context: 2B                                                      0.0s
 => [1/3] FROM docker.io/library/nginx:1.27.4                                        0.0s
 => [2/3] RUN mkdir /usr/share/nginx/html -p                                         0.3s
 => [3/3] RUN echo "hello docker" > /usr/share/nginx/html/index.html                 0.5s
 => exporting to image                                                               0.0s
 => => exporting layers                                                              0.0s
 => => writing image sha256:7c6af446d495a180d79138a4abfc5c2b99d9b0f639a9e7e3c6bc8b8  0.0s
 => => naming to docker.io/library/mynginx:v1.0                                      0.0s

 1 warning found (use docker --debug to expand):
 - MaintainerDeprecated: Maintainer instruction is deprecated in favor of using label (line 2)

[root@Docker-kd www]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
mynginx      v1.0      7c6af446d495   3 minutes ago   192MB
tomcat       11.0.5    e8c9a002d37b   7 weeks ago     467MB
nginx        1.27.4    4cad75abc83d   2 months ago    192MB
mysql        8.4.4     4a8a163431d3   3 months ago    769MB
busybox      latest    ff7a7936e930   7 months ago    4.28MB
# 运行
[root@Docker-kd www]# docker run --rm -it mynginx:v1.0 /bin/bash
root@741204f40a3d:/# pwd
/
root@741204f40a3d:/# ls
bin   docker-entrypoint.d   home   media  proc	sbin  tmp
boot  docker-entrypoint.sh  lib    mnt	  root	srv   usr
dev   etc		    lib64  opt	  run	sys   var
root@741204f40a3d:/# cd /usr/share/nginx/html/
root@741204f40a3d:/usr/share/nginx/html# ls
50x.html  index.html
root@741204f40a3d:/usr/share/nginx/html# exit
exit

二、Dockerfile 指令详解

2.1 FROM

FROM 指令必须是 Dockerfile 中非注释行的第一个指令 ,即一个 Dockerfile 从FROM 语句开始,如果FROM语句没有指定镜像标签,则默认使用latest标签

FROM 指令用于为镜像文件构建过程指定基础镜像

FROM可以在一个 Dockerfile 中出现多次,如果有需求在一个 Dockerfile 中创建多个镜像。

如果FROM语句没有指定镜像标签,则默认使用latest标签

  • 命令格式如下:
shell 复制代码
FROM [--platform=<platform>] <image> [AS <name>]
或者
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
或者
FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]

FROM <image>[:<tag>]
FROM busybox:latest

2.2 MAINTAINER

指定维护者信,可以不写。

  • 命令格式如下:
shell 复制代码
MAINTAINER <authtor's detail>

例如:
FROM busybox:latest
MAINTAINER "jock <jock@docker.com>"

2.3 COPY

用于从 docker 宿主机复制文件或者目录至创建的新镜像中的路径下,目标路径不存在时,会自动创建

  • 命令格式如下:
shell 复制代码
COPY <src>... <dest>
或
COPY ["<src>",... "<dest>"]
shell 复制代码
# COPY文件:
FROM busybox:latest
MAINTAINER "jock <jock@docker.com>"
COPY index.html /data/web/html/

#构建:
# 在dockerfile同级目录下准备好index.html文件
[root@localhost ~]# vim index.html
<h1>Busybox httpd server</h1>
[root@localhost ~]# docker build -t busyboxhttpd:v0.1 ./

#运行:
[root@localhost ~]# docker run --name web1 --rm busyboxhttpd:v0.1 cat /data/web/html/index.html
<h1>Busybox httpd server</h1>
shell 复制代码
# COPY 目录
vim index.html
<h1>Busybox httpd server</h1>
FROM busybox:latest
MAINTAINER "jock <jock@docker.com>"
COPY index.html /data/web/html/
COPY yum.repos.d /etc/yum.repos.d/

注:如果是复制目录 ,则其内部文件或子目录会被递归复制,但目录自身不会被复制;需要把复制目录名字也写在容器中要复制的路径下

shell 复制代码
#构建:
# 在dockerfile同级目录下准备好index.html文件
[root@localhost ~]# vim index.html
<h1>Busybox httpd server</h1>
[root@localhost ~]# docker build -t busyboxhttpd:v0.1 ./

#运行:
[root@localhost ~]# docker run --name web1 --rm busyboxhttpd:v0.2 ls /etc/yum.repos.d/
along.repo
docker-ce.repo
epel-release-latest-7.noarch.rpm
epel-testing.repo
epel.repo

当使用本地目录为源目录时,推荐使用 COPY

2.4 ADD

ADD 指令类似于COPY指令,ADD支持使用TAR文件和URL路径 ,该命令将复制指定的路径下的内容到容器中的路径下

  • 命令格式如下:
shell 复制代码
ADD <src> .. <dest>
或
ADD ["<src>".. "<dest>"]

与COPY的区别

1、Dockerfile 中的 COPY 指令和 ADD 指令都可以将主机上的资源复制或加入到容器镜像中 ,都是在构建镜像的过程中完成的。

2、COPY 指令和 ADD 指令的区别在于是否支持从远程 URL 获取资源

COPY 指令只能从执行 docker build 所在的主机上读取资源并复制到镜像中

而 ADD 指令还支持通过 URL 从远程服务器读取资源并复制到镜像中

3、满足同等功能的情况下,推荐使用 COPY 指令。ADD 指令更擅长读取本地 tar 文件并解压缩

4、当要读取 URL 远程资源的时候,并不推荐使用 ADD 指令,而是建议使用 RUN 指令,在 RUN 指令中执行 wget 或 curl 命令。

  • COPY 网上路径(URL)的tar包
shell 复制代码
# COPY 网上路径(URL)的tar包
FROM busybox:latest
MAINTAINER "jock <jock@docker.com>"
COPY index.html /data/web/html/
COPY yum.repos.d /etc/yum.repos.d/
ADD http://nginx.org/download/nginx-1.15.8.tar.gz /usr/local/src/
#注:ADD 的 是网上的nginx下载路径

#构建:
[root@localhost img1]# docker build -t busyboxhttpd:v0.3 ./

#运行:
[root@localhost ~]# docker run --name web1 --rm busyboxhttpd:v0.3 ls
/usr/local/src
nginx-1.15.8.tar.gz
  • COPY 本地的路径的tar包
shell 复制代码
FROM busybox:latest
MAINTAINER "jock <jock@docker.com>"
COPY index.html /data/web/html/
COPY yum.repos.d /etc/yum.repos.d/
ADD nginx-1.15.8.tar.gz /usr/local/src/

#构建:
# 在dockerfile同级目录下准备好yum.repos.d 目录
[root@localhost img1]# wget http://nginx.org/download/nginx-
1.15.8.tar.gz
[root@localhost img1]# docker build -t busyboxhttpd:v0.4 ./

#运行:
[root@localhost ~]# docker run --name web1 --rm busyboxhttpd:v0.4 ls
/usr/local/src /usr/local/src/nginx-1.15.8
/usr/local/src:
nginx-1.15.8

/usr/local/src/nginx-1.15.8:
CHANGES
CHANGES.ru
LICENSE
README
auto
conf
configure
contrib
html
man
src

2.5 WORKDIR

用于为 Dockerfile 中所有的 RUN、CMD、ENTRYPOINT、COPY 和 ADD 指定设定工作目录

  • 命令格式如下:
shell 复制代码
WORKDIR <dirpath>

在 Dockerfile 文件中,WORKDIR 指令可出现多次 ,其路径也可以为相对路径 ,不过,其是相对此前一个 WORKDIR 指令指定的路径。另外,WORKDIR 也可调用由ENV指定定义的变量

shell 复制代码
eg.
FROM busybox:latest
MAINTAINER "jock <jock@docker.com>"

COPY index.html /data/web/html/
COPY yum.repos.d /etc/yum.repos.d/

WORKDIR /usr/local/

ADD nginx-1.15.8.tar.gz ./src/

2.6 VOLUME

用于在镜像中创建一个 挂载点 目录 ,以挂载 Docker host 上的卷或其它容器上的卷

  • 命令格式如下:
shell 复制代码
VOLUME <mountpoint>
或
VOLUME ["<mountpoint>"]

注:如果挂载点目录路径下此前在文件存在,docker run命令会在卷挂载完成后将此前的所有文件复制到新挂载的卷中

shell 复制代码
# eg.

FROM busybox:latest
MAINTAINER "jock <jock@docker.com>"

COPY index.html /data/web/html/
COPY yum.repos.d /etc/yum.repos.d/

WORKDIR /usr/local/
ADD nginx-1.15.8.tar.gz ./src/

VOLUME /data/mysql
shell 复制代码
# 构建:
[root@localhost ~]# docker build -t busyboxhttpd:v0.5 ./

# 运行:[root@localhost ~]# docker run --name web1 --rm -it busyboxhttpd:v0.5
/bin/sh
/usr/local #
--- 另打开一个终端,查询存储卷
[root@localhost ~]# docker inspect -f {{.Mounts}} web1
[{volume
b788b8a50d69953e2b086b3b54ba683154647319a481246cb7ab2ff927b21372
/var/lib/docker/volumes/b788b8a50d69953e2b086b3b54ba683154647319a48124
6cb7ab2ff927b21372/_data /data/mysql local true }]

2.7 EXPOSE

用于为容器打开指定要监听的端口以实现与外部通信

  • 命令格式如下:
shell 复制代码
EXPOSE <port>[/ <protocol>] [<port>[/ <protocol>] ....
shell 复制代码
FROM busybox:latest
MAINTAINER "jock <jock@docker.com>"

COPY index.html /data/web/html/
COPY yum.repos.d /etc/yum.repos.d/

WORKDIR /usr/local/
ADD nginx-1.15.8.tar.gz ./src/

VOLUME /data/mysql

EXPOSE 80/tcp

注:就算dockerfile 中有EXPOSE 指令暴露端口,但是不是真正的暴露;需要在启动容器时,使用 -p 选项真正的暴露端口

shell 复制代码
# 构建
[root@localhost img1]# docker build -t busyboxhttpd:v0.6 ./

# 运行
[root@localhost ~]# docker run --name web1 -P --rm -it
busyboxhttpd:v0.6 /bin/httpd -f -h /data/web/html
--- 另打开一个终端,验证httpd 服务的80端口
[root@localhost ~]# docker inspect -f {{.NetworkSettings.IPAddress}}
web1 #查询容器的IP
172.17.0.2
[root@localhost ~]# curl 172.17.0.2:80
<h1>Busybox httpd server</h1>
--- 在宿主机通过暴露的端口访问httpd 服务
[root@localhost ~]# docker port web1
80/tcp -> 0.0.0.0:32768
[root@localhost ~]# curl 127.0.0.1:32768
<h1>Busybox httpd server</h1>

2.8 ENV

用于为镜像定义所需的环境变量 ,并可被 Dockerfile 文件中位于其后的其它指令(如 ENV、ADD、COPY 等)所调用,调用格式为variable_ name 或 {variable_ name}

  • 命令格式如下:
shell 复制代码
ENV <key> <value>
或
ENV <key>=<value> ...
shell 复制代码
FROM busybox:latest
MAINTAINER "jock <jock@docker.com>"

ENV DOC_ROOT=/data/web/html/ \
	WEB_SERVER_PACKAGE="nginx-1.15.8"

COPY index.html ${DOC_ROOT}
COPY yum.repos.d /etc/yum.repos.d/

WORKDIR /usr/local/
ADD ${WEB_SERVER_PACKAGE}.tar.gz ./src/

VOLUME /data/mysql

EXPOSE 8080:80/tcp
shell 复制代码
# 构建
[root@localhost ~]# docker build -t busyboxhttpd:v0.7 ./

# 运行
[root@localhost ~]# docker run --name web1 -P --rm -it
busyboxhttpd:v0.7 ls /usr/local/src /data/web/html
/data/web/html:
index.html

/usr/local/src:
nginx-1.15.8
--- 也可以使用printenv 查看变量验证
[root@localhost ~]# docker run --name web1 --rm -it busyboxhttpd:v0.7
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
DOC_ROOT=/data/web/html/
WEB_SERVER_PACKAGE=nginx-1.15.8
--- 在启动容器时,使用docker run -e 设置修改变量
[root@localhost ~]# docker run --name web1 -e
WEB_SERVER_PACKAGE=nginx-1.15.7 --rm -it busyboxhttpd:v0.7 printenv
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
WEB_SERVER_PACKAGE=nginx-1.15.7
DOC_ROOT=/data/web/html/

2.9 RUN

用于指定 docker build 过程中运行的程序,其可以是任何命令

  • 命令格式如下:
shell 复制代码
RUN <command>
或
RUN ["<executable>", "<param1>", "<param2>"]
shell 复制代码
FROM busybox:latest
MAINTAINER "jock <jock@docker.com>"

ENV DOC_ROOT=/data/web/html/ \
	WEB_SERVER_PACKAGE="nginx-1.15.8.tar.gz"

COPY index.html ${DOC_ROOT}
COPY yum.repos.d /etc/yum.repos.d/

WORKDIR /usr/local/
ADD http://nginx.org/download/${WEB_SERVER_PACKAGE} ./src/

VOLUME /data/mysql

EXPOSE 8080:80/tcp

RUN cd ./src && \
	tar -xf ${WEB_SERVER_PACKAGE}
shell 复制代码
# 构建
[root@localhost ~]# docker build -t busyboxhttpd:v0.8 ./

# 运行
[root@localhost ~]# docker run --name web1 -P --rm -it
busyboxhttpd:v0.7 ls /usr/local/src
nginx-1.15.8

2.10 CMD

类似于 RUN 指令,CMD 指令也可用于运行任何命令或应用程序

  • 不同点:

    • RUN 指令运行于映像文件构建过程中,而 CMD 指令运行于基于 Dockerfile 构建出的新映像文件启动一个容器时。
    • CMD 指令首要目的在于为启动的容器指定默认要运行的程序,且其运行结束后,容器也将终止。不过,CMD 指定的命令其可以被 docker run 的命令行选项所覆盖。
    • 在 Dockerfile 中可存在多个 CMD 指令,但仅最后一个会生效
  • 命令格式如下:

shell 复制代码
CMD <command>
或
CMD ["<executable>","<param1>","<param2>"]
或
CMD ["<param1>","<param2>"]

注:

前两种语法格式的意义同 RUN。

第三种则用于为 ENTRYPOINT 指令提供默认参数。

JSON 数组中,要使用双引号,单引号会出错。

shell 复制代码
FROM busybox
MAINTAINER "jock <jock@docker.com>"

ENV WEB_DOC_ROOT="/data/web/html"

RUN mkdir -p ${WEB_DOC_ROOT} && \
	echo "<h1>Busybox httpd server</h1>" > ${WEB_DOC_ROOT}/index.html

CMD /bin/httpd -f -h ${WEB_DOC_ROOT}
shell 复制代码
# 构建
docker build -t busyboxhttpd:v1.1 ./

# 运行
[root@localhost ~]# docker run --name web2 --rm -d busyboxhttpd:v1.1
20aa07198943887db51173e245392f75e3654525cb32242f2b04f0b3e007e47d
[root@localhost ~]# docker inspect -f {{.NetworkSettings.IPAddress}}
web2
172.17.0.2
[root@localhost ~]# curl 172.17.0.2
<h1>Busybox httpd server</h1>

使用CMD定义的命令,在启动容器时,会被后面追加的指令覆盖;与下面ENTRYPOINT 指令对比
[root@localhost ~]# docker kill web2
web2
[root@localhost ~]# docker run --name web2 --rm busyboxhttpd:v1.1 ls /
bin
data
dev
etc
[root@localhost ~]# curl 172.17.0.2 被ls /覆盖,所以没有执行httpd服务

2.11 ENTRYPOINT

类似 CMD 指令的功能,用于为容器指定默认运行程序,从而使得容器像是一个单独的可执行程序。

与 CMD 不同的是,由 ENTRYPOINT 启动的程序不会被 docker run 命令行指定的参数所覆盖,而且,这些命令行参数会被当作参数传递给ENTRYPOINT 指定指定的程序。

不过,docker run 命令的 --entrypoint 选项的参数可覆盖 ENTRYPOINT 指令指定的程序

  • 命令格式如下:
shell 复制代码
ENTRYPOINT <command>
ENTRYPOINT ["<executable>", "<param1>", "<param2>"]

注:

docker run 命令传入的命令参数会覆盖 CMD 指令的内容并且附加到 ENTRYPOINT 命令最后做为其参数使用。

Dockerfile 文件中也可以存在多个 ENTRYPOINT 指令,但仅有最后一个会生效

shell 复制代码
FROM busybox
MAINTAINER "jock <jock@docker.com>"

ENV WEB_DOC_ROOT="/data/web/html"

RUN mkdir -p ${WEB_DOC_ROOT} && \
	echo "<h1>Busybox httpd server</h1>" > ${WEB_DOC_ROOT}/index.html
	
ENTRYPOINT /bin/httpd -f -h ${WEB_DOC_ROOT}
shell 复制代码
# 构建
[root@localhost ~]# docker build -t busyboxhttpd:v1.2 ./

# 运行
[root@localhost ~]# docker run --name web2 --rm busyboxhttpd:v1.2 ls /
发现是不会执行ls / 这个命令;仍然执行的是ENTRYPOINT中设置的命令;与上面CMD 指令对比;
[root@localhost ~]# curl 172.17.0.2 #httpd服务仍然执行,没有被ls / 指令覆盖
<h1>Busybox httpd server</h1>

三、Dockerfile 创建镜像与模板

3.1 Dockerfile 镜像

编写完成 Dockerfile 之后,可以通过 docker build 命令来创建镜像

基本的格式为:

powershell 复制代码
docker build [选项] 内容路径

该命令将读取指定路径下(包括子目录)的 Dockerfile,并将该路径下的所有内容发送给Docker服务端,由服务端来创建镜像

powershell 复制代码
# 如果使用非内容路径下的Dockerfile,可以通过-f选项来指定其路径
docker build -t lagou/ubuntu:v1 .
#docker build 最后的 . 号,其实是在指定镜像构建过程中的上下文环境的目录

3.2 镜像管理

Docker 镜像由一系列层组成。每层代表镜像的 Dockerfile 中的一条指令。除最后一层外的每一层都是只读的

shell 复制代码
# 该 Dockerfile 包含四个命令,每个命令创建一个层
FROM ubuntu:18.04	#从 ubuntu:18.04 镜像创建只读层
COPY . /app		#从 Docker 客户端的当前目录添加一些文件
RUN make /app	#使用命令构建应用程序 make
CMD python /app/app.py	#最后一层指定在容器中运行什么命令

运行镜像并生成容器时,可以在基础层之上添加一个新的可写层("容器层")。对运行中的容器所做的所有更改(例如写入新文件,修改现有文件和删除文件)都将写入此可写容器层

容器和镜像之间的主要区别是可写顶层

在容器中添加新数据或修改现有数据的所有写操作都存储在此可写层中。删除容器后,可写层也会被删除。基础镜像保持不变。

因为每个容器都有其自己的可写容器层,并且所有更改都存储在该容器层中,所以多个容器可以共享对同一基础镜像的访问,但具有自己的数据状态

  • 查看镜像的分层信息
shell 复制代码
docker history 镜像ID
  • 要查看正在运行的容器的大致大小,可以使用以下 docker ps -s 命令
    • size :用于每个容器的可写层的数据量(在磁盘上)
    • virtual size :容器使用的只读图像数据加上容器的可写层使用的数据量size
      多个容器可以共享部分或全部只读图像数据。从同一图像开始的两个容器共享100%的只读数据,而具有不同图像的两个容器(具有相同的层)共享这些公共层
shell 复制代码
# 可以通过Docker仓库来传输我们的镜像,也可以通过文件模式
docker save 镜像ID -o xxxx.tar 或(docker save xxxx > xxxx.tar)

docker load -i xxxx.tar 或docker (docker load < xxxx.tar)

docker diff 容器ID

docker commit 容器ID openlab/testimage:version4 # 直接保存容器

docker commit --change='CMD ["apachectl", "-DFOREGROUND"]' -c "EXPOSE 80" 容器ID openlab/testimage:version4 # 将正在运行的容器添加几个层之后再保存】

3.3 Dockerfile 模板

通过最小化Dockerfile中RUN 单独命令的数量来减少镜像中的层数。可以通过将多个命令合并为RUN 一行并使用Shell的机制将它们组合在一起来实现此目的

shell 复制代码
#在镜像中创建两层
RUN apt-get -y update
RUN apt-get install -y python

#在镜像中创建一层
RUN apt-get -y update && apt-get install -y python

3.3.1 Redhat 镜像模板

dockerfile-redhat:

shell 复制代码
# 依据哪个镜像创建
From centos:7.6.1810

# 指定容器内部使用语言
ENV LANG="en_US.UTF-8"
ENV LC_ALL="en_US.UTF-8"
# 使用亚洲/上海时区
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# 创建工作目录
RUN mkdir -p /data/apps /data/data /data/logs ; ln -s /data/apps /apps
# 安装字体
RUN yum install -y epel-release
RUN yum groupinstall -y "fonts"
RUN yum install -y kde-l10n-Chinese
# 安装openssl等依赖包
RUN yum install -y openssl openssl-devel
RUN yum install -y crontabs cronolog ntp
# 安装数据库依赖
RUN yum install -y mariadb-libs
RUN ln -s /usr/lib64/mysql/libmysqlclient.so.18
/usr/lib64/libmysqlclient_r.so.16
RUN yum install -y gcc cmake
RUN yum install -y lrzsz telnet net-tools file bind-utils less
RUN yum install -y jq xml2; yum clean all
RUN yum install -y expat-devel apr-devel ghostscript ghostscript-devel
# 运行容器时的默认命令
CMD ["/bin/bash"]
  • 构建命令:
shell 复制代码
docker build -f dockerfile-redhat -t lagou/centos/7.6/centos .
docker run --rm -it lagou/centos/7.6/centos

# 使用 Red Hat 9 作为基础镜像
FROM registry.access.redhat.com/ubi9/ubi:latest

# 设置时区为亚洲/上海
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ >
/etc/timezone

# 安装中文语言包
RUN dnf install -y kde-l10n-Chinese

# 安装 openssl 和其他依赖包
RUN dnf install -y openssl openssl-devel

# 安装 MySQL 8.4.4 的依赖
RUN dnf install -y \
libaio \
numactl-libs \
libtirpc \
libedit \
ncurses-compat-libs \
wget \
tar

# 下载并安装 MySQL 8.4.4
RUN wget https://dev.mysql.com/get/Downloads/MySQL-8.4/mysql-8.4.4-
linux-glibc2.28-x86_64.tar.gz -O /tmp/mysql.tar.gz && \
tar -xzf /tmp/mysql.tar.gz -C /opt && \
mv /opt/mysql-8.4.4-linux-glibc2.28-x86_64 /opt/mysql && \
rm -f /tmp/mysql.tar.gz

# 设置 MySQL 环境变量
ENV PATH=/opt/mysql/bin:$PATH

# 创建 MySQL 数据目录
RUN mkdir -p /var/lib/mysql && \
chown -R mysql:mysql /var/lib/mysql

# 初始化 MySQL
RUN mysqld --initialize-insecure --user=mysql --basedir=/opt/mysql --
datadir=/var/lib/mysql

# 暴露 MySQL 默认端口
EXPOSE 3306

# 设置容器启动时运行的命令
CMD ["mysqld", "--user=mysql"]
  • 构建和运行命令:
shell 复制代码
docker build -t redhat9-mysql8.4.4 .
docker run -d --name mysql-container -p 3306:3306 redhat9-mysql8.4.4

3.3.2 JDK 镜像模板

dockerfile-jdk:

shell 复制代码
# 使用 Red Hat 9 作为基础镜像
FROM registry.access.redhat.com/ubi9/ubi:latest

# 设置时区为亚洲/上海
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ >
/etc/timezone

# 安装必要的工具
RUN dnf install -y \
wget \
tar \
gzip \
&& dnf clean all

# 下载并安装 JDK 21
# 注意:请根据实际需求替换 JDK 21 的下载链接
RUN wget
https://download.java.net/java/GA/jdk21/fd2272bbf8e04c3dbaee1377009041
6c/35/GPL/openjdk-21_linux-x64_bin.tar.gz -O /tmp/jdk21.tar.gz && \
tar -xzf /tmp/jdk21.tar.gz -C /opt && \
mv /opt/jdk-21 /opt/jdk && \
rm -f /tmp/jdk21.tar.gz

# 设置 JDK 环境变量
ENV JAVA_HOME=/opt/jdk
ENV PATH=$JAVA_HOME/bin:$PATH

# 验证安装
RUN java -version

# 设置工作目录
WORKDIR /app

# 默认启动命令(可以根据需要修改)
CMD ["java", "-version"]
  • 构建命令:
shell 复制代码
docker build -t redhat9-jdk21 .
docker run -it --rm redhat9-jdk21

3.3.3 Tomcat 镜像模板

dockerfile-jdk:

shell 复制代码
# 使用 Red Hat 9 作为基础镜像
FROM registry.access.redhat.com/ubi9/ubi:latest

# 设置时区为亚洲/上海
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ >
/etc/timezone

# 安装必要的工具
RUN dnf install -y \
wget \
tar \
gzip \
&& dnf clean all

# 下载并安装 JDK 21
RUN wget
https://download.java.net/java/GA/jdk21/fd2272bbf8e04c3dbaee1377009041
6c/35/GPL/openjdk-21_linux-x64_bin.tar.gz -O /tmp/jdk21.tar.gz && \
	tar -xzf /tmp/jdk21.tar.gz -C /opt && \
	mv /opt/jdk-21 /opt/jdk && \
	rm -f /tmp/jdk21.tar.gz

# 设置 JDK 环境变量
ENV JAVA_HOME=/opt/jdk
ENV PATH=$JAVA_HOME/bin:$PATH

# 验证 JDK 安装
RUN java -version

# 下载并安装 Tomcat 11.0.5
RUN wget https://archive.apache.org/dist/tomcat/tomcat-
11/v11.0.5/bin/apache-tomcat-11.0.5.tar.gz -O /tmp/tomcat.tar.gz && \
	tar -xzf /tmp/tomcat.tar.gz -C /opt && \
	mv /opt/apache-tomcat-11.0.5 /opt/tomcat && \
	rm -f /tmp/tomcat.tar.gz
	
# 设置 Tomcat 环境变量
ENV CATALINA_HOME=/opt/tomcat
ENV PATH=$CATALINA_HOME/bin:$PATH

# 创建 Tomcat 用户和组
RUN groupadd -r tomcat && \
	useradd -r -g tomcat -d $CATALINA_HOME -s /bin/false tomcat && \
	chown -R tomcat:tomcat $CATALINA_HOME

# 暴露 Tomcat 默认端口
EXPOSE 8080

# 设置工作目录
WORKDIR $CATALINA_HOME

# 切换为 Tomcat 用户
USER tomcat

# 启动 Tomcat
CMD ["catalina.sh", "run"]
  • 构建:
shell 复制代码
# 构建
docker build -t redhat9-tomcat11.0.5 .

# 运行
docker run -d --name tomcat-container -p 8080:8080 redhat9-
tomcat11.0.5

访问:

打开浏览器,访问 http://localhost:8080 ,即可看到 Tomcat 的默认页面

  • 注意事项:
    • 如果需要部署自定义的 WAR 文件,可以将 WAR 文件复制到 /opt/tomcat/webapps 目录。
    • 如果需要持久化 Tomcat 的日志或配置文件,可以使用 Docker 卷( volumes )。
    • 如果需要调整 Tomcat 的配置,可以修改 /opt/tomcat/conf 目录下的配置文件。

四、Docker 数据持久化

  1. 创建一个卷,待后边使用
shell 复制代码
docker volume create test_volume
  1. 分别启动2个容器挂在上卷
shell 复制代码
# 在2个终端窗口启动2个容器
docker run -it --rm -v test_volume:/test nginx:1.27.4 /bin/bash
docker run -it --rm -v test_volume:/test nginx:1.27.4 /bin/bash
cd /test;
touch a.txt
ls /test

# 在两个容器中我们均可以看到我们创建的文件,这样我们就可以做到了在多个容器之间实现数据共享

挂载在容器/test 目录内创建

Docker 不支持容器内安装点的相对路径。 多个容器可以在同一时间段内使用相同的卷。如果两个容器需要访问共享数据,这将很有用

注意:如果宿主机上的目录可以不存在,会在启动容器的时候创建

五、案例实战

5.1 构建nginx服务镜像

powershell 复制代码
[root@docker ~]# ls
anaconda-ks.cfg  elasticsearch.yml  index3.html          redis:7.4.2.tar.gz
centos_7.tar.gz  index2.html        nginx.1.27.4.tag.gz
[root@docker ~]# docker load -i centos_7.tar.gz 
174f56854903: Loading layer  211.7MB/211.7MB
Loaded image: centos:7
[root@docker ~]# docker images
REPOSITORY      TAG       IMAGE ID       CREATED        SIZE
redis           latest    65750d044ac8   3 months ago   117MB
busybox         latest    ff7a7936e930   7 months ago   4.28MB
centos          7         eeb6ee3f44bd   3 years ago    204MB



[root@docker ~]# mkdir demo
[root@docker ~]# cd demo/
[root@docker demo]# ls
[root@docker demo]# vim Dockerfile
[root@docker demo]# ls
Dockerfile
[root@docker demo]# cat Dockerfile 
FROM centos:7

MAINTAINER jock 1062080730@qq.com

RUN mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup

RUN curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && \
    curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo

RUN yum install -y wget make gcc gcc-c++ pcre-devel zlib-devel openssl-devel && \
    yum clean all

RUN wget https://nginx.org/download/nginx-1.24.0.tar.gz && \
    tar -zxf nginx-1.24.0.tar.gz && \
    rm nginx-1.24.0.tar.gz

WORKDIR /nginx-1.24.0
RUN ./configure --prefix=/usr/local/nginx --with-http_ssl_module && \
    make && \
    make install

RUN mkdir -p /usr/local/nginx/html && \
    echo "hello jock | welcome to nginx! | version 1.0" > /usr/local/nginx/html/index.html

RUN echo '#!/bin/bash' > /start.sh && \
    echo 'hostname > /usr/local/nginx/html/hostname.html' >> /start.sh && \
    echo '/usr/local/nginx/sbin/nginx -g "daemon off;"' >> /start.sh && \
    chmod +x /start.sh

EXPOSE 80

CMD ["/start.sh"]
powershell 复制代码
[root@docker demo]# docker build -t myapp1.0 .
[+] Building 147.5s (13/13) FINISHED                                       docker:default
 => [internal] load build definition from Dockerfile                                 0.0s
 => => transferring dockerfile: 1.14kB                                               0.0s
 => WARN: MaintainerDeprecated: Maintainer instruction is deprecated in favor of us  0.0s
 => [internal] load metadata for docker.io/library/centos:7                          0.0s
 => [internal] load .dockerignore                                                    0.0s
 => => transferring context: 2B                                                      0.0s
 => [1/9] FROM docker.io/library/centos:7                                            0.0s
 => [2/9] RUN mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.rep  0.2s
 => [3/9] RUN curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/r  0.4s
 => [4/9] RUN yum install -y wget make gcc gcc-c++ pcre-devel zlib-devel openssl-  123.0s
 => [5/9] RUN wget https://nginx.org/download/nginx-1.24.0.tar.gz &&     tar -zxf n  2.4s 
 => [6/9] WORKDIR /nginx-1.24.0                                                      0.0s 
 => [7/9] RUN ./configure --prefix=/usr/local/nginx --with-http_ssl_module &&       20.7s 
 => [8/9] RUN mkdir -p /usr/local/nginx/html &&     echo "hello jock | welcome to n  0.1s 
 => [9/9] RUN echo '#!/bin/bash' > /start.sh &&     echo 'hostname > /usr/local/ngi  0.1s 
 => exporting to image                                                               0.5s 
 => => exporting layers                                                              0.5s 
 => => writing image sha256:9fc60c39bb353c478d9ddffd9599c5d5be1b3667a199a7b849aa0bf  0.0s 
 => => naming to docker.io/library/myapp1.0                                          0.0s 

 1 warning found (use docker --debug to expand):
 - MaintainerDeprecated: Maintainer instruction is deprecated in favor of using label (line 3)

[root@docker demo]# docker run --name myapp -d -p 80:80 myapp1.0:latest 
ded4100304c454ca8871f9db9384eb2736e6382cfad289e270262e43d85616e9
[root@docker demo]# docker ps
CONTAINER ID   IMAGE             COMMAND       CREATED          STATUS          PORTS                                 NAMES
ded4100304c4   myapp1.0:latest   "/start.sh"   11 seconds ago   Up 10 seconds   0.0.0.0:80->80/tcp, [::]:80->80/tcp   myapp
[root@docker demo]# curl localhost
hello jock | welcome to nginx! | version 1.0
[root@docker demo]# curl localhost/hostname.html
ded4100304c4
  • nginx
powershell 复制代码
[root@docker demo]# rm -rf *
[root@docker demo]# vim Dockerfile
[root@docker demo]# cat Dockerfile
FROM centos:7

MAINTAINER jock 1062080730@qq.com

RUN mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup

RUN curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && \
    curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo

RUN yum -y install epel-release && \
    yum -y install nginx && \
    yum clean all

COPY error.html /usr/share/nginx/html/error.html

RUN echo 'server { error_page 404 /error.html; location = /error.html { root /usr/share/nginx/html; } }' > /etc/nginx/conf.d/default.conf

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]
[root@docker demo]# vim error.html
[root@docker demo]# cat error.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>自定义错误页面</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            text-align: center;
            padding: 50px;
        }
        h1 {
            color: #333;
        }
        p {
            color: #666;
        }
    </style>
</head>
<body>
    <h1>哎呀!页面未找到</h1>
    <p>你所请求的页面可能已经被移除或者地址错误。</p>
</body>
</html>
[root@docker demo]# ls
Dockerfile  error.html
powershell 复制代码
[root@docker demo]# docker build -t error:1.0 .
[+] Building 34.6s (11/11) FINISHED                                        docker:default
 => [internal] load build definition from Dockerfile                                 0.0s
 => => transferring dockerfile: 732B                                                 0.0s
 => WARN: MaintainerDeprecated: Maintainer instruction is deprecated in favor of us  0.0s
 => [internal] load metadata for docker.io/library/centos:7                          0.0s
 => [internal] load .dockerignore                                                    0.0s
 => => transferring context: 2B                                                      0.0s
 => [1/6] FROM docker.io/library/centos:7                                            0.0s
 => [internal] load build context                                                    0.0s
 => => transferring context: 674B                                                    0.0s
 => CACHED [2/6] RUN mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-B  0.0s
 => CACHED [3/6] RUN curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyu  0.0s
 => [4/6] RUN yum -y install epel-release &&     yum -y install nginx &&     yum c  34.3s
 => [5/6] COPY error.html /usr/share/nginx/html/error.html                           0.0s
 => [6/6] RUN echo 'server { error_page 404 /error.html; location = /error.html { r  0.2s
 => exporting to image                                                               0.2s 
 => => exporting layers                                                              0.2s 
 => => writing image sha256:f658b54fa24cce7c0322ff844402e5917495b98650df3e43e78ff33  0.0s 
 => => naming to docker.io/library/error:1.0                                         0.0s 

 1 warning found (use docker --debug to expand):
 - MaintainerDeprecated: Maintainer instruction is deprecated in favor of using label (line 3)

[root@docker demo]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
error        1.0       f658b54fa24c   28 seconds ago   262MB
myapp        1.0       c48517613d32   7 minutes ago    210MB
myapp1.0     latest    9fc60c39bb35   15 minutes ago   368MB
kibana       8.17.3    7dcda0c152aa   7 weeks ago      1.18GB
mysql        8.4.4     4a8a163431d3   3 months ago     769MB
centos       7         eeb6ee3f44bd   3 years ago      204MB
[root@docker demo]# docker run --name error -d -p 80:80 error:1.0 
aeb56da0b8e066c9b135937f8e10ac934ba5e3fe3f87cd126b75e8a2e4409c04
[root@docker demo]# docker ps
CONTAINER ID   IMAGE       COMMAND                  CREATED         STATUS         PORTS                                 NAMES
aeb56da0b8e0   error:1.0   "nginx -g 'daemon of..."   4 seconds ago   Up 3 seconds   0.0.0.0:80->80/tcp, [::]:80->80/tcp   error
[root@docker demo]# curl localhost/error.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>自定义错误页面</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            text-align: center;
            padding: 50px;
        }
        h1 {
            color: #333;
        }
        p {
            color: #666;
        }
    </style>
</head>
<body>
    <h1>哎呀!页面未找到</h1>
    <p>你所请求的页面可能已经被移除或者地址错误。</p>
</body>
</html>
  • go
shell 复制代码
[root@docker demo]# vim main.go
[root@docker demo]# cat main.go 
package main

import (
	"log"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Hello, HTTPS!"))
	})

	log.Println("Server running on https://localhost:443")
	err := http.ListenAndServeTLS(":443", "server.crt", "server.key", nil)
	if err != nil {
		log.Fatal("ListenAndServeTLS: ", err)
	}
}

[root@docker demo]# openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
    -keyout server.key -out server.crt \
    -subj "/C=CN/ST=Demo/L=Demo/O=Demo/CN=localhost"
.............+++++++++++++++++++++++++++++++++++++++*..+...+..+............+.+........+....+..+++++++++++++++++++++++++++++++++++++++*.+.......+.....+......+....+..............+.+.........+...........+.+..+............+.+..+......+.......+...+.........+..+.+.....+....+...+........+...+.......+........+......+.+...............+.....+....+......+............+..+.........+....+.....................+............+..+.+..+....+........+............+.+.................+..........+..+.+.....+...+......+.............+......+......+...+...+..+......+....+..+.+.........+.....+.............+..+.+............+..+....+..+...+.........+.+..+....+.....+.............+......+......++++++
....+....+...+...........+....+...+..+++++++++++++++++++++++++++++++++++++++*.........+....+......+.................+...+.+...+......+..+++++++++++++++++++++++++++++++++++++++*.+.+.........+......+......+.........+.....+...+...+...+.+........+..........+..+.........+.........+.......+.....+..........+...+......+..+...+.+...+...+..+.+...........+.+........+......+................+............+..+.............+.....+...+...+.....................+..........+..................+...+..................+..+.......+..+....+.....................+...+...+..............+.+...............+..+......+.........+......+.+.....+......+...+....+..+...+...+............+.+......+......+...+...........+.+...+............+..+...+...+......+.+..+............+.+..............+....+..+....+..............+.+...+..........................++++++
-----

[root@docker demo]# vim Dockerfile
[root@docker demo]# cat Dockerfile
FROM golang:alpine

MAINTAINER jock 1062080730@qq.com

WORKDIR /app

COPY main.go .

RUN go build -o main main.go

COPY server.crt .
COPY server.key .

EXPOSE 443

CMD ["./main"]
shell 复制代码
shell 复制代码
shell 复制代码
shell 复制代码
shell 复制代码
相关推荐
沙子迷了蜗牛眼6 分钟前
当展示列表使用 URL.createObjectURL 的创建临时图片、视频无法加载问题
java·前端·javascript·vue.js
ganshenml8 分钟前
【Android】 开发四角版本全解析:AS、AGP、Gradle 与 JDK 的配套关系
android·java·开发语言
我命由我123458 分钟前
Kotlin 运算符 - == 运算符与 === 运算符
android·java·开发语言·java-ee·kotlin·android studio·android-studio
小途软件15 分钟前
ssm327校园二手交易平台的设计与实现+vue
java·人工智能·pytorch·python·深度学习·语言模型
alonewolf_9919 分钟前
Java类加载机制深度解析:从双亲委派到热加载实战
java·开发语言
追梦者12320 分钟前
springboot整合minio
java·spring boot·后端
云游23 分钟前
Jaspersoft Studio community edition 7.0.3的应用
java·报表
菜鸟思维27 分钟前
优化NextJs 项目的Docker 镜像 从3.62G 优化到 296.85M
docker
帅气的你28 分钟前
Spring Boot 集成 AOP 实现日志记录与接口权限校验
java·spring boot
怣疯knight42 分钟前
Docker Desktop 4.55.0版本安装成功教程
windows·docker