-----承接 Docker 容器(三)续写
8. Docker****镜像的创建
Docker 提供了多种方式来创建镜像,常见的有三种方法:基于已有镜像创建、基于本地模板创建和基于 Dockerfile 创建。以下是这三种方法的详细介绍。
8.1****基于现有镜像创建
8.1.1****启动容器并做修改
① 首先,通过 docker create 启动一个容器并进入其 bash 环境:
docker create -it centos:7 /bin/bash
-it 参数表示交互式运行, /bin/bash 表示启动 bash shell。
② 查看当前容器的状态:
docker ps -a
③ 修改容器内部的环境(例如安装软件包、修改配置文件等),然后退出容器。
8.1.2****提交容器为新的镜像
完成容器内的修改后,可以通过 docker commit 命令将容器提交为新的镜像:
docker commit -m "new" -a "centos" eeb6ee3f44bd centos:test
-m : 提交说明。
-a : 作者信息。
eeb6ee3f44bd: 容器 ID。
centos:test : 创建的新镜像名称。
查看创建的新镜像:
docker images
8.2****基于本地模板创建
通过导入模板文件,可以创建一个新的镜像。模板通常可以从开源项目(如 OPENVZ)中获取。
8.2.1****下载操作系统模板
例如,下载 Debian 模板:
下载地址为http://openvz.org/Download/template/precreated
wget http://download.openvz.org/template/precreated/debian-7.0-x86-minimal.tar.gz
也可以使用 curl 下载:
curl -L 下载路径 -o 保存路径
wget 下载路径
8.2.2导入为Docker****镜像
将模板文件导入为 Docker 镜像:
cat debian-7.0-x86-minimal.tar.gz | docker import - debian:test
这里 debian:test 是新创建的镜像名称。
8.3基于Dockerfile****创建 重点
Dockerfile 是一个文本文件,其中包含了一系列的指令,每个指令创建一个新的镜像层。通过 Dockerfile,我们可以实现镜像的自动化构建。
8.3.1 Docker****镜像的分层结构
镜像分层:Docker 镜像不是单一文件,而是由多层文件系统组成。每执行一条 Dockerfile 指令,都会生成新的镜像层。容器启动时会在镜像的只读层上添加一层可读写层。
镜像缓存:Docker 会缓存每一层的镜像,如果某一层的内容没有变化,则会复用缓存层,以提高构建效率。
bash
//联合文件系统(UnionFS)
UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持
对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。AUFS、OverlayFS 及 Devicemapper 都是一种 UnionFS。
Union文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。
下载的时候看到的一层层的就是联合文件系统。
//镜像加载原理
Docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统就是UnionFS。
bootfs主要包含bootloader和kernel,bootloader主要是引导加载kernel,Linux刚启动时会加载bootfs文件系统。
在Docker镜像的最底层是bootfs,这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs,在bootfs之上。包含的就是典型Linux系统中的/dev,/proc,/bin,/etc等标准目录和文件。
rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。
可以理解成一开始内核里什么都没有,操作一个命令下载debian,这时就会在内核上面加了一层基础镜像;再安装一个emacs,会在基础镜像上叠加一层image;接着再安装一个apache,又会在images上面再叠加一层image。
最后它们看起来就像一个文件系统即容器的rootfs。在Docker的体系里把这些rootfs叫做Docker的镜像。
但是,此时的每一层rootfs都是read-only的,我们此时还不能对其进行操作。当我们创建一个容器,也就是将Docker镜像进行实例化,系统会在一层或是多层read-only的rootfs之上分配一层空的read-write的rootfs。
//为什么Docker里的centos的大小才200M?
因为对于精简的OS,rootfs可以很小,只需要包含最基本的命令、工具和程序库就可以了,因为底层直接用宿主机的kernel,自己只需要提供rootfs就可以了。由此可见对于不同的linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版可以公用bootfs。
Dockerfile基本细说
bash
Docker镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。
镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。
Dockerfile是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。有了Dockerfile,当我们需要定制自己额外的需求时,只需在Dockerfile上添加或者修改指令,重新生成 image 即可, 省去了敲命令的麻烦。
除了手动生成Docker镜像之外,可以使用Dockerfile自动生成镜像。Dockerfile是由多条的指令组成的文件,其中每条指令对应 Linux 中的一条命令,Docker 程序将读取Dockerfile 中的指令生成指定镜像。
Dockerfile结构大致分为四个部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。
Dockerfile每行支持一条指令,每条指令可携带多个参数,支持使用以"#"号开头的注释。
#Docker 镜像结构的分层
镜像不是一个单一的文件,而是有多层构成。容器其实是在镜像的最上面加了一层读写层,在运行容器里做的任何文件改动,都会写到这个读写层。如果删除了容器,也就删除了其最上面的读写层,文件改动也就丢失了。
Docker使用存储驱动管理镜像每层内容及可读写层的容器层。
(1)Dockerfile 中的每个指令都会创建一个新的镜像层;
(2)镜像层将被缓存和复用;
(3)当Dockerfile 的指令修改了,复制的文件变化了,或者构建镜像时指定的变量不同了,对应的镜像层缓存就会失效;
(4)某一层的镜像缓存失效,它之后的镜像层缓存都会失效;
(5)镜像层是不可变的,如果在某一层中添加一个文件,然后在下一层中删除它,则镜像中依然会包含该文件,只是这个文件在 Docker 容器中不可见了。
基于图更好理解




8.3.2 Dockerfile****操作常用指令
以下是 Dockerfile 中常用的指令:
1) FROM
指定新镜像基于的基础镜像,Dockerfile 的第一条指令必须为 FROM 。
bash
FROM centos:7
2) MAINTAINER
指定镜像的维护者信息:
bash
MAINTAINER "John Doe <johndoe@example.com>"
- RUN
执行命令并将结果提交到镜像中。常用来安装软件包、修改配置等。
bash
RUN yum install -y httpd
- ENTRYPOINT
设置容器启动时默认执行的命令:
bash
ENTRYPOINT ["httpd"]
- CMD
容器启动时执行的默认命令。 CMD 指令会被 docker run 命令后指定的命令覆盖。
bash
CMD ["httpd", "-D", "FOREGROUND"]
- EXPOSE
声明容器内的端口:
bash
EXPOSE 80
- ENV
设置环境变量:
bash
ENV MY_VAR=my_value
- ADD
将文件或目录从宿主机复制到镜像中,支持从 URL 下载文件,并能自动解压归档文件:
bash
ADD myfile.tar.gz /app
- COPY
将本地文件或目录复制到镜像中:
bash
COPY . /app
- VOLUME
在容器中创建挂载点:
bash
VOLUME ["/data"]
- USER
设置容器内运行命令时的用户:
bash
USER root
- WORKDIR
设置后续指令的工作目录:
bash
WORKDIR /app
- ONBUILD
设置当该镜像作为基础镜像时,后续 Dockerfile 执行的命令:
bash
ONBUILD RUN echo "Building from base image"
- HEALTHCHECK
设置容器的健康检查:
bash
HEALTHCHECK CMD curl --fail http://localhost:8080 || exit 1
8.3.3 Dockerfile****示例
以下是一个简单的 Dockerfile 示例:
bash
# 使用 CentOS 7 作为基础镜像
#建立工作目录
mkdir /opt/apache
cd /opt/apache
vim Dockerfile
#基于的基础镜像
FROM centos:7
#维护镜像的用户信息
MAINTAINER this is apache image <hmj>
#镜像操作指令安装apache软件
ADD CentOS-Base.repo /etc/yum.repos.d/
RUN yum clean all
RUN yum -y update
RUN yum -y install httpd
#开启 80 端口
EXPOSE 80
#复制网站首页文件
ADD index.html /var/www/html/index.html
//方法一:
#将执行脚本复制到镜像中
ADD run.sh /run.sh
RUN chmod 755 /run.sh
#启动容器时执行脚本
CMD ["/run.sh"]
//方法二:
ENTRYPOINT [ "/usr/sbin/apachectl" ]
CMD ["-D", "FOREGROUND"]
//方法三
# 启动 httpd 服务
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]
准备执行脚本(方式一)
vim run.sh
#!/bin/bash
rm -rf /run/httpd/* #清理httpd的缓存
/usr/sbin/apachectl -D FOREGROUND #指定为前台运行
#因为Docker容器仅在它的1号进程(PID为1)运行时,会保持运行。如果1号进程退出了,Docker容器也就退出了。
//准备网站页面
echo "this is test web" > index.html
//生成镜像
docker build -t httpd:centos . #注意别忘了末尾有"."
//新镜像运行容器
docker run -d -p 1216:80 httpd:centos
//测试
http://192.168.10.61:1216/



8.3.4****构建镜像
使用以下命令构建镜像:
bash
docker build -t my-web-server .
这将根据当前目录下的 Dockerfile 构建一个名为 my-web-server 的镜像。
8.3.5****镜像的分层和缓存
每一条 Dockerfile 指令都会创建一个新的镜像层。
Docker 会缓存每一层的镜像,只有在指令或文件发生变化时,才会重新构建该层及其之后的层。
镜像层是不可变的,删除容器时只会删除其上面的读写层,底层的镜像层不会丢失。
8.4****总结
Docker 镜像的创建方式多种多样,常用的有:
基于现有镜像创建:通过修改容器并提交为新的镜像。
基于本地模板创建:从模板文件导入创建镜像。
基于 Dockerfile****创建:通过编写 Dockerfile 来定制镜像,支持自动化构建。
9. Docker Compose****编排
9.1****简介
通过 Docker Compose,我们可以在一个 YAML 配置文件中定义多个服务,并实现容器之间的联动,简化了应用的部署和管理。
Docker-Compose项目是Docker官方的开源项目,负责实现对Docker容器集群的快速编排。 Docker-Compose将所管理的容器分为三层,分别是工程(project),服务(service)以及容器 (container)。Docker-Compose运行目录下的所有文件(docker-compose.yml,extends文件或环境变量文件等)组成一个工程,若无特殊指定工程名即为当前目录名。一个工程当中可包含多个服务, 每个服务中定义了容器运行的镜像、参数、依赖。一个服务当中可包括多个容器实例,Docker-Compose并没有解决负载均衡的问题,因此需要借助其它工具实现服务发现及负载均衡,比如 Consul。
Docker-Compose的工程配置文件默认为docker-compose.yml,可通过环境变量COMPOSE_FILE或-f参数自定义配置文件,其定义了多个有依赖关系的服务及每个服务运行的容器。
使用一个Dockerfile模板文件,可以让用户很方便的定义一个单独的应用容器。在工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个Web项目,除了Web服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡容器等。
LNMP docker-comes 搭建lnmp 并且 做论坛 wordpress
Compose允许用户通过一个单独的docker-compose.yml模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。
Docker-Compose项目由Python编写,调用Docker服务提供的API来对容器进行管理。因此,只要所操作的平台支持Docker API, 就可以在其上利用Compose来进行编排管理
在 Web 应用中,常常需要将前端的请求通过反向代理转发到后端应用服务器。在这里,我们将使用 Docker Compose来编排 Nginx和 Tomcat两个服务。Nginx 将作为前端的反向代理服务器,接收客户端请求并将其转发到后端的 Tomcat 容器。Tomcat 则负责处理 Web 应用的请求。
9.2****项目结构
Docker Compose 环境安装
bash
#下载
curl -L https://github.com/docker/compose/releases/download/1.21.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
#安装
chmod +x /usr/local/bin/docker-compose
#查看版本
docker-compose --version
新的版本下载地址
sudo curl -L "https://github.com/docker/compose/releases/download/2.26.0/docker-composelinux-aarch64" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
9.3 YAML****文件格式及编写注意事项
YAML(YAML Ain't Markup Language)是一种简洁的数据序列化格式,常用于配置文件。它比 JSON 更加简洁易读,并且支持更复杂的数据结构。使用 YAML 编写 Docker Compose 配置文件时,有几个 注意事项:
9.3.1 YAML****基本语法
大小写敏感:YAML 是大小写敏感的,所以一定要注意区分大小写。
缩进:YAML 使用空格进行缩进,不支持TAB缩进。通常推荐使用两个空格作为一个层级的缩进。
列表:列表项使用 - (短横线)表示。
字典:字典使用 : (冒号)连接键值对,冒号后面需要加一个空格。
注释:使用 # 来添加注释。
字符串:如果字符串包含特殊字符,可以使用单引号 ' 或双引号 " 来包裹。
数据结构:
bash
●对象映射: 键值对的字典
animal: pets
●序列数组: 一组按次序排列的列表
- Cat
- Dog
- Goldfish
["Cat", "Dog", "Goldfish"]
●布尔值
debug: true
debug: false
示例:
# yaml 格式
languages: #序列的映射
- Java
- Golang
- Python
websites: #映射的映射
cpu: 2
memory: 1024M
swap: 2048M
disk: 60G
键:{值}
# Json 格式
{
languages: [
'Java',
'Golang',
'Python'
],
resources: {
cpu: '2',
memory: '1024M',
swap: '2048M',
disk: '60G'
}
}
Baidu:
www.baidu.com
ftp.baidu.com
wangyi: www.163.com
tengxun: www.qq.com
9.3.2 Docker Compose****配置常用字段
bash
字段 描述
build 指定 Dockerfile 文件名,要指定Dockerfile文件需要在build标签的子级标签中使用dockerfile标签指定
dockerfile 构建镜像上下文路径
context 可以是 dockerfile 的路径,或者是指向 git 仓库的 url 地址
image 指定镜像
command: 执行命令,覆盖容器启动后默认执行的命令
container_name 指定容器名称,由于容器名称是唯一的,如果指定自定义名称,则无法scale指定容器数量
deploy 指定部署和运行服务相关配置,只能在 Swarm 模式使用
environment 添加环境变量
networks 加入网络,引用顶级networks下条目
network_mode 设置容器的网络模式,如 host,bridge,...
ports 暴露容器端口,与 -p 相同,但端口不能低于 60
volumes 挂载一个宿主机目录或命令卷到容器,命名卷要在顶级
volumes 定义卷名称
volumes_from 从另一个服务或容器挂载卷,可选参数 :ro 和 :rw,仅版本 '2' 支持
hostname 容器主机名
sysctls 在容器内设置内核参数
links 连接到另外一个容器,- 服务名称[:服务别名]
privileged 用来给容器root权限,注意是不安全的,true | false
restart 设置重启策略,no,always,nounless-stfailure,oped no,默认策略,在容器退出时不重启容器。
on-failure,在容器非正常退出时(退出状态非0),才会重启容器。
on-failure:3,在容器非正常退出时重启容器,最多重启3次。
always,在容器退出时总是重启容器。
unless-stopped,在容器退出的容器时总是重启容器,但是不考虑在 Docker 守护进程启动时就已经停止了。
depends_on
在使用Compose时,最大的好处就是少打启动命令,但一般项目容器启动的顺序是有要求的,如果直接从上到下启动容器,可能会因为容器依赖问题而启动失败。例如在没启动数据库容器的时候启动应用容器,应用容器会因为找不到数据库而退出。depends_on标签用于解决容器的依赖、启动先后的问题。
php:
depends_on:
- apache
- mysql
9.3.3 Docker Compose****常用命令
bash
字段 描述
build 重新构建服务
ps 列出容器
up 创建和启动容器
exec 在容器里面执行命令
scale 指定一个服务容器启动数量
top 显示容器进程
logs 查看容器输出
down 删除容器、网络、数据卷和镜像
stop/start/restart 停止/启动/重启服务
9.3.4 Docker Compose****文件结构
bash
/opt/compose_nginx_tomcat/
├── docker-compose.yml # Docker Compose 配置文件
├── nginx
│ ├── Dockerfile # Nginx 镜像的 Dockerfile
│ └── nginx.conf # Nginx 配置文件
├── tomcat
│ ├── Dockerfile # Tomcat 镜像的 Dockerfile
│ └── webapps
│ └── ROOT.war # Tomcat 应用的 WAR 包
└── wwwroot
└── index.html # 静态文件,Nginx 显示的页面
9.3.5 YAML****示例
① 准备依赖文件
bash
mkdir -p /opt/compose_nginx/nginx /opt/compose_nginx/wwwroot
cd /opt/compose_nginx/nginx
cp nginx-1.20.2.tar.gz ./
vim run.sh
#!/bin/bash
/usr/local/nginx/sbin/nginx
vim Dockerfile
#基于基础镜像
FROM centos:7
#用户信息
MAINTAINER this is nginx image <xiao>
#添加环境包
RUN rm -rf /etc/yum.repos.d/*
ADD CentOS-Base.repo /etc/yum.repos.d/
RUN yum clean all && yum makecache && \
yum -y install gcc gcc-c++ make pcre-devel zlib-devel && \
useradd -M -s /sbin/nologin nginx
#上传nginx软件压缩包,并解压
ADD nginx-1.20.2.tar.gz /usr/local/src/
#指定工作目录
WORKDIR /usr/local/src/nginx-1.20.2/
RUN ./configure \
--prefix=/usr/local/nginx/ \
--user=nginx \
--group=nginx \
--with-http_stub_status_module && make && make install
ENV PTAH /usr/local/nginx/sbin:$PATH
#指定http和https端口
EXPOSE 80
EXPOSE 443
//方法一:
RUN echo "daemon off;" >> /usr/local/nginx/conf/nginx.conf #关闭 nginx 在后台运行
#添加宿主机中run.sh到容器中
ADD run.sh /run.sh
RUN chmod 755 /run.sh
CMD ["/run.sh"]
//方法二:
ENTRYPOINT [ "/usr/local/nginx/sbin/nginx", "-g", "daemon off;" ]
echo "<h1>this is test web</h1>" > /opt/compose_nginx/wwwroot/index.html
② 编写配置文件****docker-compose.yml
bash
vim /opt/compose_nginx/docker-compose.yml
version: '3'
services:
nginx:
container_name: web1
hostname: nginx
build:
context: ./nginx
dockerfile: Dockerfile
ports:
- 1216:80
- 1217:443
networks:
lnmp:
ipv4_address: 172.18.0.10
volumes:
- ./wwwroot:/usr/local/nginx/html
networks:
lnmp:
driver: bridge
ipam:
config:
- subnet: 172.18.0.0/16
cd /opt/compose_nginx/
docker-compose -f docker-compose.yml up -d
----------------------------------------------------------------------------------------------------------
-f, --file FILE :使用特定的 compose 模板文件,默认为 docker-compose.yml
-p, --project-name NAME :指定项目名称,默认使用目录名称
-d :在后台运行
----------------------------------------------------------------------------------------------------------
cd /opt/compose_nginx/
docker-compose ps #必须在docker-compose.yml所在目录执行此命令


9.3.3****编写注意事项
文件路径:在 docker-compose.yml 文件中, context 和 volumes 路径都是相对路径,相对于 docker-compose.yml 文件所在的目录。
字段区分:YAML 格式中, services 下定义的每个服务都会有自己的配置项,例如 image 、 build 、 ports 等。确保每个字段的位置和缩进正确。
服务间的依赖关系:例如, depends_on 可以控制服务启动的顺序,确保依赖的服务先启动。
9.4准备Nginx****配置
在 nginx/nginx.conf 中,配置 Nginx 作为反向代理,转发请求到 Tomcat 服务:
bash
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://tomcat:8080; # 将请求转发给 Tomcat 服务
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
proxy_pass http://tomcat:8080 表示将请求转发到名为 tomcat 的服务(在 Compose 中, 这个名称会自动解析为 Tomcat 容器的名称)。
配置 proxy_set_header 是为了确保转发请求时,Nginx 会把客户端的 IP 和请求头传递给后端服务器。
9.5****编写docker**-**compose.yml
编写 docker-compose.yml 配置文件,定义 Nginx 和 Tomcat 两个服务。以下是一个完整的示例:
bash
version: '3'
services:
nginx:
container_name: web1
hostname: nginx
build:
context: ./nginx
dockerfile: Dockerfile
ports:
- 1216:80 # 将宿主机的8081端口映射到Nginx的80端口
- 1217:443
networks:
lnmp:
ipv4_address: 172.18.0.10
volumes:
- ./wwwroot:/usr/local/nginx/html # 映射静态文件目录
depends_on:
- tomcat # 确保Tomcat容器先启动
tomcat:
container_name: tomcat
hostname: tomcat
build:
context: ./tomcat
dockerfile: Dockerfile
ports:
- 8080:8080 # 将宿主机的8080端口映射到Tomcat的8080端口
networks:
lnmp:
driver: bridge
ipam:
config:
- subnet: 172.18.0.0/16
depends_on 确保 Nginx 服务启动时,Tomcat 服务已启动并运行。
networks 部分将两个服务连接到同一个 Docker 网络 app_network ,保证它们之间可以相互通信。
9.6****启动服务
完成以上配置后,可以通过 docker-compose 启动项目:
bash
cd /opt/compose_nginx
docker-compose up -d
# -d 参数表示在后台运行容器。


