Bootstrap

Docker容器技术

目录

一、Docker简介及部署方法

1、Docker简介

docker与虚拟化的对比

2、rhel9部署docker

(1)容器工作方法

(2)部署

1)配置软件仓库

2)安装docker-ce

二、Docker的基本操作

1、Docker镜像管理

(1)搜索镜像

(2)拉取镜像 

(3)查看镜像信息

(4)导出镜像

(5)删除镜像

(6)镜像测试 

2、容器的常用操作

(1)启动容器

(2)查看容器运行信息

(3)停止和运行容器

(4)删除容器

(5)容器内容提交

(6)系统中的文件和容器中的文件传输

(7)查询容器内部日志

三、docker镜像构建

1、docker镜像结构

2、镜像运行的基本原理

3、镜像获得方式

4、镜像构建

(1)构建参数

(2)Dockerfile实例

1)建立构建目录,编写构建文件

2)通过dockerfile生成镜像

3)测试镜像可用性

4)查看容器详情

5、镜像优化方案

(1)镜像优化策略

(2)镜像优化示例

方法一:缩减镜像层

方法二:多阶段构建

方法三:使用最精简镜像

四、docker 镜像仓库的管理

1、docker仓库

2、docker公有仓库

(1)官网https://hub.docker.com/进行注册登录

(2)登录信息保存位置

(3)打标记上传docker

3、docker仓库的工作原理

(1)pull原理

(2)push原理

4、搭建docker的私有仓库

(1)下载Registry镜像

(2)开启Registry

(3)上传镜像到仓库中

(4)为Registry提加密传输

(5)为仓库建立登陆认证

5、构建企业级私有仓库

(1)部署harbor

(2)docker的webUI工具

五、Docker 网络

1、docker原生bridge网路

2、docker原生网络host

3、docker 原生网络none

4、docker的自定义网络

(1)自定义桥接网络

(2)如何让不同的自定义网络互通?

(3)joined容器网络

演示:利用容器部署phpmyadmin管理mysql

5、容器内外网的访问

(1)容器访问外网

(2)外网访问docker容器

6、docker跨主机网络

(1)CNM(Container Network Model)

(2)macvlan网络方式实现跨主机通信

macvlan网络方式

macvlan网络间的隔离和连通

实现方法

六、Docker 数据卷管理及优化

1、为什么要用数据卷

docker分层文件系统

docker数据卷

docker提供了两种卷

2、bind mount 数据卷

3、docker managed 数据卷

4、数据卷容器(Data Volume Container)

(1)建立数据卷容器

(2)使用数据卷容器

5、bind mount 数据卷和docker managed 数据卷的对比

6、备份与迁移数据卷

(1)备份数据卷

(2)数据恢复

七、Docker 的安全优化

命名空间隔离的安全

控制组资源控制的安全

内核能力机制

Docker服务端防护

1、Docker的资源限制

(1)限制CPU使用

(2)限制CPU的优先级

(3)限制内存使用

法一

法二:自建控制器

(4)限制docker的磁盘io

2、Docker的安全加固

(1)Docker默认隔离性

(2)解决Docker的默认隔离性

(3)容器特权

(4)容器特权的白名单

八、容器编排工具Docker Compose

1、Docker Compose 概述

2、Docker Compose 的常用命令参数

(1)服务管理

docker compose up

docker compose down

docker compose start

docker compose stop

docker compose restart

(2)服务状态查看

docker compose ps

docker compose logs 

(3)构建和重新构建服务

docker-compose build

docker compose up --build

(4)其他操作

docker-compose exec

docker-compose pull

docker-compose config

3、Docker Compose 的yml文件

(1)服务

服务名称(service1_name/service2_name 等)

环境变量(environment)

(2)网络(networks)

3、存储卷

4、企业示例


一、Docker简介及部署方法

1、Docker简介

Docker是管理容器的引擎,为应用打包、部署平台,而非单纯的虚拟化技术

它具有以下几个重要特点和优势:

  • 1. 轻量级虚拟化
  • 2. 一致性
  • 3. 可移植性
  • 4. 高效的资源利用
  • 5. 易于部署和扩展

docker与虚拟化的对比

虚拟机docker容器
操作系统宿主机上运行虚拟机OS共享宿主机OS
存储镜像较大(GB)镜像小(MB)
性能操作系统额外的cpu、内存消耗几乎无性能损耗
移植性笨重、与虚拟化技术耦合度高轻量、灵活迁移
隔离性完全隔离安全隔离
部署慢、分钟级快速、秒级
运行密度一般几十个单机支持上千容器

2、rhel9部署docker

(1)容器工作方法

(2)部署

1)配置软件仓库

[root@docker-node1 ~]# cd /etc/yum.repos.d/
[root@docker-node1 yum.repos.d]# ls
redhat.repo  rhel9.repo
[root@docker-node1 yum.repos.d]# vim docker.repo
[root@docker-node1 yum.repos.d]# cat dockere.repo
[docker]
name=docker
baseurl=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/rhel/9/x86_64/stable/
gpgcheck=0
2)安装docker-ce

法一

[root@docker-node1 yum.repos.d]# yum search docker-ce
[root@docker-node1 yum.repos.d]# yum install -y docker-ce.x86_64

法二

[root@docker-node1 ~]# ls
anaconda-ks.cfg  Desktop  docker.tar.gz  Documents  Downloads  Music  Pictures  Public  Templates  Videos  zuoyedir
[root@docker-node1 ~]# tar zxf docker.tar.gz 
[root@docker-node1 ~]# ls
anaconda-ks.cfg                               docker-ce-cli-27.1.2-1.el9.x86_64.rpm              Downloads  Videos
containerd.io-1.7.20-3.1.el9.x86_64.rpm       docker-ce-rootless-extras-27.1.2-1.el9.x86_64.rpm  Music      zuoyedir
Desktop                                       docker-compose-plugin-2.29.1-1.el9.x86_64.rpm      Pictures
docker-buildx-plugin-0.16.2-1.el9.x86_64.rpm  docker.tar.gz                                      Public
docker-ce-27.1.2-1.el9.x86_64.rpm             Documents                                          Templates
[root@docker-node1 ~]# dnf install *.rpm -y

[root@docker-node1 ~]# systemctl enable --now docker
Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /usr/lib/systemd/system/docker.service.

[root@docker-node1 ~]# docker info

https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors
# 配置镜像加速器
[root@docker-node1 ~]# cd /etc/docker/
[root@docker-node1 docker]# vim daemon.json
[root@docker-node1 docker]# cat daemon.json
{
    "registry-mirrors": ["https://y3w6d9eb.mirror.aliyuncs.com"]
}

二、Docker的基本操作

1、Docker镜像管理

(1)搜索镜像

[root@docker-node1 ~]# docker search nginx
NAME                              DESCRIPTION                                     STARS     OFFICIAL
nginx                             Official build of Nginx.                        20126     [OK]
参数说明
NAME镜像名称
DESCRIPTION镜像说明
STARS点赞数量
OFFICIAL是否是官方的

(2)拉取镜像 

[root@docker-node1 ~]# docker pull busybox

[root@docker-node1 ~]# ls
anaconda-ks.cfg                               docker-ce-rootless-extras-27.1.2-1.el9.x86_64.rpm  Music
busybox-latest.tar.gz                         docker-compose-plugin-2.29.1-1.el9.x86_64.rpm      nginx-latest.tar.gz
containerd.io-1.7.20-3.1.el9.x86_64.rpm       docker.tar.gz                                      Pictures
Desktop                                       Documents                                          Public
docker-buildx-plugin-0.16.2-1.el9.x86_64.rpm  Downloads                                          Templates
docker-ce-27.1.2-1.el9.x86_64.rpm             game2048.tar.gz                                    Videos
docker-ce-cli-27.1.2-1.el9.x86_64.rpm         mario.tar.gz                                       zuoyedir

[root@docker-node1 ~]# docker load -i game2048.tar.gz 
[root@docker-node1 ~]# docker load -i mario.tar.gz
[root@docker-node1 ~]# docker load -i nginx-latest.tar.gz
[root@docker-node1 ~]# docker load -i busybox-latest.tar.gz

[root@docker-node1 ~]# docker images
REPOSITORY           TAG       IMAGE ID       CREATED         SIZE
nginx                latest    5ef79149e0ec   13 days ago     188MB
busybox              latest    65ad0d468eb1   15 months ago   4.26MB
timinglee/game2048   latest    19299002fdbe   7 years ago     55.5MB
timinglee/mario      latest    9a35a9e43e8c   8 years ago     198MB

(3)查看镜像信息

[root@docker-node1 ~]# docker image inspect nginx:latest 

 查看镜像结构

(4)导出镜像

-o:指定导出镜像的位置

可以同时导出多个镜像到一个文件中,指定.tar.gz 可以导出并压缩

[root@docker-node1 ~]# docker image save nginx:latest -o nginx-latest.tar.gz

#保存所有镜像
[root@docker-node1 ~]# docker save `docker images | awk 'NR>1{print $1":"$2}'` -o images.tar.gz

(5)删除镜像

[root@docker-node1 ~]# docker rmi nginx:latest
[root@docker-node1 ~]# docker rmi `docker images | awk 'NR>1{print $1":"$2}'`

(6)镜像测试 

[root@docker-node1 ~]# docker run -d --rm --name webserver -p 80:80 nginx
3c2ade3d9c9258c7c571a36f8a9aa5e919f6844fdc2fcc0508ed34e356e72982
[root@docker-node1 ~]# 
[root@docker-node1 ~]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS         PORTS                               NAMES
3c2ade3d9c92   nginx     "/docker-entrypoint.…"   10 seconds ago   Up 9 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp   webserver

[root@docker-node1 ~]# docker rm -f webserver
webserver

[root@docker-node1 ~]# docker run -d --rm --name game1 -p 80:8080 timinglee/mario:latest
3feb451086de8c9ce53df2ab2354f504a799d6efd37ef5da03b1a5598d7631be

[root@docker-node1 ~]# docker rm -f game1
game1

2、容器的常用操作

(1)启动容器

[root@docker-node1 ~]# docker run -d --name mario -p 80:8080 timinglee/mario

-d             #后台运行
-i             #交互式运行
-t             #打开一个终端
--name         #指定容器名称
-p             #端口映射 -p 80:8080 把容器8080端口映射到本机80端口
--rm           #容器停止自动删除容器
--network      #指定容器使用的网络
[root@docker-node1 ~]# docker run -it --name test busybox    # #进入到容器中,按<ctrl>+<d>退出并停止容器,#按<ctrl>+<pq>退出但不停止容器

/ # 
/ # ls
bin    dev    etc    home   lib    lib64  proc   root   sys    tmp    usr    var
/ # date
Wed Aug 28 10:02:58 UTC 2024
/ # 
/ # exit
[root@docker-node1 ~]# date
Wed Aug 28 06:03:05 PM CST 2024

# 重新进入容器
[root@docker-node1 ~]# docker attach test
/ # 
/ # 
/ #

# 删除容器
[root@docker-node1 ~]# docker rm test
test

#在容器中执行命令
[root@docker-node1 ~]# docker start test
[root@docker-node1 ~]# docker exec -it test ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:03  
          inet addr:172.17.0.3  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:16 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:2086 (2.0 KiB)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

(2)查看容器运行信息

#查看当前运行容器
[root@docker-node1 ~]# docker ps
CONTAINER ID   IMAGE             COMMAND                  CREATED          STATUS          PORTS                                   NAMES
edb72465fb76   timinglee/mario   "python3 -m http.ser…"   11 minutes ago   Up 11 minutes   0.0.0.0:80->8080/tcp, :::80->8080/tcp   mario

#查看所有容器
[root@docker-node1 ~]# docker ps -a
CONTAINER ID   IMAGE             COMMAND                  CREATED          STATUS                     PORTS                                   NAMES
4e676f3fc287   busybox           "sh"                     8 seconds ago    Exited (0) 3 seconds ago                                           test
edb72465fb76   timinglee/mario   "python3 -m http.ser…"   11 minutes ago   Up 11 minutes              0.0.0.0:80->8080/tcp, :::80->8080/tcp   mario

#查看容器运行的详细信息
[root@docker-node1 ~]# docker inspect busybox

(3)停止和运行容器

容器内的第一个进程必须一直处于运行的状态,否则这个容器,就会处于退出状态!

#停止容器
[root@docker-node1 ~]# docker stop test

#杀死容器,可以使用信号
[root@docker-node1 ~]# docker kill test

#开启停止的容器
[root@docker-node1 ~]# docker start test
test

[root@docker-node1 ~]# docker ps -a    # 查看是否停止开启

(4)删除容器

#删除停止的容器
[root@docker-node1 ~]# docker rm  test

#删除运行的容器
[root@docker-node1 ~]# docker rm -f test

#删除所有停止的容器
[root@docker-node1 ~]# docker container prune -f

#删除建立所有失败的容器
[root@docker-node1 docker]# docker rmi `docker images | awk '/none/{print $3}'`

#通配符匹配删除容器
[root@docker-node1 docker]# docker rmi busybox:v{1,2}
Untagged: busybox:v1
Deleted: sha256:4f5a1e92b339f1982ff0c33e2d2a64336ecbe7259c54b9b76818add068fd5f60
Deleted: sha256:36ba2277cefa7e88834017d08732f9b5cfc60a6f1602e0e06774185972999471
Untagged: busybox:v2
Deleted: sha256:f9ed1b274e05538f5797574ecfc25aa68ce2b24055b018f05131f96f7c4c74a8

(5)容器内容提交

  • 默认情况下,容器被删除后,在容器中的所有操作都会被清理,包括要保存的文件
  • 如果想永久保存,那么需要把动作提交,提交后会生成新的镜像
  • 当在运行新镜像后即可看到提交的内容
[root@docker-node1 ~]# docker run -it --name test busybox
/ # touch zx-file
/ # ls
bin      dev      etc      home     lib      lib64    proc     root     sys      tmp      usr      var      zx-file
/ # exit
[root@docker-node1 ~]# docker rm test
test
[root@docker-node1 ~]# docker run -it --name test busybox
/ # ls
bin    dev    etc    home   lib    lib64  proc   root   sys    tmp    usr    var
/ # [root@docker-node1 ~]# 
[root@docker-node1 ~]# docker commit -m "add zx-file" test busybox:v1
sha256:4f5a1e92b339f1982ff0c33e2d2a64336ecbe7259c54b9b76818add068fd5f60
[root@docker-node1 ~]# 
[root@docker-node1 ~]# docker images
REPOSITORY           TAG       IMAGE ID       CREATED         SIZE
busybox              v1        4f5a1e92b339   5 seconds ago   4.26MB
nginx                latest    5ef79149e0ec   13 days ago     188MB
busybox              latest    65ad0d468eb1   15 months ago   4.26MB
timinglee/game2048   latest    19299002fdbe   7 years ago     55.5MB
timinglee/mario      latest    9a35a9e43e8c   8 years ago     198MB
[root@docker-node1 ~]# 
[root@docker-node1 ~]# docker image history busybox:v1

(6)系统中的文件和容器中的文件传输

#把容器中的文件复制到本机
[root@docker-node1 ~]# docker cp test:/zx-file /root
Successfully copied 1.54kB to /root

#把本机文件复制到容器中
[root@docker-node1 ~]# docker cp zx-file-new test:/root
Successfully copied 1.54kB to test:/root
[root@docker-node1 ~]# docker attach test
/ # cd root/
~ # ls
zx-file-new

(7)查询容器内部日志

[root@docker-node1 ~]# docker logs test

三、docker镜像构建

1、docker镜像结构

  • 共享宿主机的kernel
  • base镜像提供的是最小的Linux发行版
  • 同一docker主机支持运行多种Linux发行版
  • 采用分层结构的最大好处是:共享资源

2、镜像运行的基本原理

  • Copy-on-Write 可写容器层
  • 容器层以下所有镜像层都是只读的
  • docker从上往下依次查找文件
  • 容器层保存镜像变化的部分,并不会对镜像本身进行任何修改
  • 一个镜像最多127层

3、镜像获得方式

  • 基本镜像通常由软件官方提供
  • 企业镜像可以用官方镜像+Dockerfile来生成
  • 系统关于镜像的获取动作有两种:
    • docker pull 镜像地址
    • docker load –i 本地镜像包

4、镜像构建

(1)构建参数

FROM

指定base镜像

eg:FROM busybox:version

COPY

复制文件

eg:COPY file /file 或者 COPY [“file”,”/”]

MAINTAINER

指定作者信息,比如邮箱

eg:MAINTAINER [email protected]

在最新版的docker中用LABEL KEY="VALUE"代替

ADD

功能和copy相似,指定压缩文件或url

eg: ADD test.tar /mnt 或者 ADD http://ip/test.tar /mnt

ENV

指定环境变量

eg:ENV FILENAME test

EXPOSE

暴漏容器端口

eg:EXPOSE 80

VOLUME

申明数据卷,通常指数据挂载点

eg:VOLUME [“/var/www/html”]

WORKDIR

切换路径

eg:WORKDIR /mnt

RUN

在容器中运行的指令

eg: touch file

CMD

在启动容器时自动运行动作可以被覆盖

eg:CMD echo $FILENAME 会调用 shell解析

eg:CMD [“/bin/sh”,”-c”,“echo $FILENAME”] 不调用shell解析

ENTRYPOINT和CMD功能和用法类似,但动作不可被覆盖
[root@docker-node1 ~]# mkdir docker/
[root@docker-node1 ~]# cd docker/
[root@docker-node1 docker]# touch zxfile
[root@docker-node1 docker]# vim Dockerfile
[root@docker-node1 docker]# cat Dockerfile 
FROM busybox:latest
LABEL [email protected]
COPY zxfile /

[root@docker-node1 docker]# docker build -t busybox:v2 .
[root@docker-node1 docker]# docker history busybox:v2
IMAGE          CREATED          CREATED BY                          SIZE      COMMENT
f9ed1b274e05   11 minutes ago   COPY zxfile / # buildkit            0B        buildkit.dockerfile.v0
<missing>      11 minutes ago   LABEL [email protected]      0B        buildkit.dockerfile.v0
<missing>      15 months ago    BusyBox 1.36.1 (glibc), Debian 12   4.26MB    

(2)Dockerfile实例

1)建立构建目录,编写构建文件
[root@docker-node1 ~]# docker load -i /root/centos-7.tar.gz 
174f56854903: Loading layer [==================================================>]  211.7MB/211.7MB
Loaded image: centos:7

[root@docker-node1 ~]# mkdir docker
[root@docker-node1 ~]# cd docker/
[root@docker-node1 docker]# cp ~/nginx-1.23.tar.gz .
[root@docker-node1 docker]# vim Dockerfile
[root@docker-node1 docker]# cat Dockerfile
FROM centos:7
ADD nginx-1.26.1.tar.gz /root
WORKDIR /root/nginx-1.26.1
RUN yum install -y gcc make pcre-devel openssl-devel
RUN ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_stub_status_module
RUN make
RUN make install
EXPOSE 80 443
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off"]
2)通过dockerfile生成镜像
[root@docker-node1 docker]# docker build -t webserver:v1 .

# 出现“=> ERROR [4/8] RUN yum install -y gcc make pcre-devel openssl-devel”错误时:新添7.9的ISO映像文件

[root@docker-node1 ~]# docker run -it --name centos centos:7
[root@docker-node1 ~]# mkdir -p /var/www/html/rhel7.9
[root@docker-node1 ~]# mount /dev/sr
sr0  sr1  
[root@docker-node1 ~]# mount /dev/sr1 /var/www/html/rhel7.9/
mount: /var/www/html/rhel7.9: WARNING: source write-protected, mounted read-only.

[root@docker-node1 yum.repos.d]# yum install httpd -y
[root@docker-node1 yum.repos.d]# vim /etc/httpd/conf/httpd.conf     # 更改端口为8888
[root@docker-node1 yum.repos.d]# systemctl start httpd

[root@docker-node1 ~]# docker attach centos
[root@9254e0ce5b5e /]# cd /etc/yum.repos.d/
[root@9254e0ce5b5e yum.repos.d]# ls
CentOS-Base.repo  CentOS-Debuginfo.repo  CentOS-Sources.repo  CentOS-fasttrack.repo
CentOS-CR.repo    CentOS-Media.repo      CentOS-Vault.repo    CentOS-x86_64-kernel.repo
[root@9254e0ce5b5e yum.repos.d]# rm -fr *
[root@9254e0ce5b5e yum.repos.d]# vi centos7.repo
[root@9254e0ce5b5e yum.repos.d]# cat centos7.repo 
[centos7]
name=centos7
baseurl=http://172.17.0.1:8888/rhel7.9
gpgcheck=0


[root@docker-node1 ~]# docker commit -m "add repo" centos centos:repo
sha256:e651ad916be95747432b9082d6497e6498365d2fba1df1f6ca4e9dc932572b95
[root@docker-node1 ~]# docker images
REPOSITORY           TAG       IMAGE ID       CREATED         SIZE
centos               repo      e651ad916be9   8 seconds ago   204MB

[root@9254e0ce5b5e yum.repos.d]# exit
exit
[root@docker-node1 ~]# 
[root@docker-node1 ~]# docker rm centos
centos

[root@docker-node1 docker]# vim Dockerfile 
[root@docker-node1 docker]# cat Dockerfile 
FROM centos:repo
ADD nginx-1.26.1.tar.gz /root
WORKDIR /root/nginx-1.26.1
RUN yum install -y gcc make pcre-devel openssl-devel
RUN ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_stub_status_module
RUN make
RUN make install
EXPOSE 80 443
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off"]

若虚拟机安装docker后ip地址没了,修改Docker网络配置
[root@docker-node1 docker]# vim /etc/docker/daemon.json 
[root@docker-node1 docker]# cat daemon.json 
{
	"bip":"172.17.0.1/16",
    	"registry-mirrors": ["https://y3w6d9eb.mirror.aliyuncs.com"]
}

[root@docker-node1 docker]# systemctl restart docker
[root@docker-node1 ~]# docker inspect centos    # 查看名为centos的docker端口IP
[root@docker-node1 docker]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.214 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.158 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.097 ms
3)测试镜像可用性
[root@docker-node1 docker]# docker images webserver
REPOSITORY   TAG       IMAGE ID       CREATED              SIZE
webserver    v1        5b17bdead0af   About a minute ago   356MB
[root@docker-node1 docker]# docker history webserver:v1 
IMAGE          CREATED              CREATED BY                                      SIZE      COMMENT
5b17bdead0af   About a minute ago   CMD ["/usr/local/nginx/sbin/nginx" "-g" "dae…   0B        buildkit.dockerfile.v0
<missing>      About a minute ago   VOLUME [/usr/local/nginx/html]                  0B        buildkit.dockerfile.v0
<missing>      About a minute ago   EXPOSE map[443/tcp:{} 80/tcp:{}]                0B        buildkit.dockerfile.v0
<missing>      About a minute ago   RUN /bin/sh -c make install # buildkit          6.11MB    buildkit.dockerfile.v0
<missing>      About a minute ago   RUN /bin/sh -c make # buildkit                  20.6MB    buildkit.dockerfile.v0
<missing>      2 minutes ago        RUN /bin/sh -c ./configure --prefix=/usr/loc…   78.9kB    buildkit.dockerfile.v0
<missing>      2 minutes ago        RUN /bin/sh -c yum install -y gcc make pcre-…   118MB     buildkit.dockerfile.v0
<missing>      3 minutes ago        WORKDIR /root/nginx-1.26.1                      0B        buildkit.dockerfile.v0
<missing>      3 minutes ago        ADD nginx-1.26.1.tar.gz /root # buildkit        7.35MB    buildkit.dockerfile.v0
<missing>      49 minutes ago       /bin/bash                                       73B       add repo
<missing>      2 years ago          /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B        
<missing>      2 years ago          /bin/sh -c #(nop)  LABEL org.label-schema.sc…   0B        
<missing>      2 years ago          /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4…   204MB  

4)查看容器详情
[root@docker-node1 docker]# docker inspect webserver:v1 

5、镜像优化方案

(1)镜像优化策略

  • 选择最精简的基础镜像
  • 减少镜像的层数
  • 清理镜像构建的中间产物
  • 选择最精简的基础镜像
  • 减少镜像的层数
  • 清理镜像构建的中间产物

(2)镜像优化示例

方法一:缩减镜像层
[root@docker-node1 docker]# docker images webserver
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
webserver    v1        5b17bdead0af   10 hours ago   356MB
[root@docker-node1 docker]# vim Dockerfile 
[root@docker-node1 docker]# cat Dockerfile 
FROM centos:repo
ADD nginx-1.26.1.tar.gz /root
WORKDIR /root/nginx-1.26.1
RUN yum install -y gcc make pcre-devel openssl-devel && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && ./configure --with-http_ssl_module --with-http_stub_status_module && make && make install && cd .. && rm -fr nginx1.23.3 && yum clean all
EXPOSE 80 443
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off"]

[root@docker-node1 docker]# docker build -t webserver:v2 .

方法二:多阶段构建
[root@docker-node1 docker]# vim Dockerfile 
[root@docker-node1 docker]# docker build -t webserver:v3 .
[root@docker-node1 docker]# docker images webserver
[root@docker-node1 docker]# cat Dockerfile 
FROM centos:repo AS build
ADD nginx-1.26.1.tar.gz /root
WORKDIR /root/nginx-1.26.1
RUN yum install -y gcc make pcre-devel openssl-devel && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && ./configure --with-http_ssl_module --with-http_stub_status_module && make && make install && cd .. && rm -fr nginx1.23.3 && yum clean all

FROM centos:repo
COPY --from=build /usr/local/nginx /usr/local/nginx
EXPOSE 80 443
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off"]

方法三:使用最精简镜像
[root@docker-node1 ~]# docker load -i nginx-1.23.tar.gz 
[root@docker-node1 ~]# docker load -i debian11.tar.gz 
[root@docker-node1 ~]# mkdir new
[root@docker-node1 ~]# cp nginx-1.23.tar.gz new/
[root@docker-node1 ~]# cp debian11.tar.gz new/
[root@docker-node1 ~]# cd new/
[root@docker-node1 new]# vim Dockerfile
[root@docker-node1 new]# cat Dockerfile 
FROM nginx:1.23 AS base
ARG TIME_ZONE
RUN mkdir -p /opt/var/cache/nginx && \
cp -a --parents /usr/lib/nginx /opt && \
cp -a --parents /usr/share/nginx /opt && \
cp -a --parents /var/log/nginx /opt && \
cp -aL --parents /var/run /opt && \
cp -a --parents /etc/nginx /opt && \
cp -a --parents /etc/passwd /opt && \
cp -a --parents /etc/group /opt && \
cp -a --parents /usr/sbin/nginx /opt && \
cp -a --parents /usr/sbin/nginx-debug /opt && \
cp -a --parents /lib/x86_64-linux-gnu/ld-* /opt && \
cp -a --parents /usr/lib/x86_64-linux-gnu/libpcre* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libz.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libc* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libdl* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libpthread* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libcrypt* /opt && \
cp -a --parents /usr/lib/x86_64-linux-gnu/libssl.so.* /opt && \
cp -a --parents /usr/lib/x86_64-linux-gnu/libcrypto.so.* /opt && \
cp /usr/share/zoneinfo/${TIME_ZONE:-ROC} /opt/etc/localtime
FROM gcr.io/distroless/base-debian11
COPY --from=base /opt /
EXPOSE 80 443
ENTRYPOINT ["nginx", "-g", "daemon off;"]

[root@docker-node1 new]# docker build -t webserver:v4 .

四、docker 镜像仓库的管理

1、docker仓库

Docker 仓库(Docker Registry) 是用于存储和分发 Docker 镜像的集中式存储库

它就像是一个大型的镜像仓库,开发者可以将自己创建的 Docker 镜像推送到仓库中,也可以从仓库中拉取所需的镜像。

Docker 仓库可以分为公共仓库和私有仓库:

  • 公共仓库,如 Docker Hub,任何人都可以访问和使用其中的镜像。许多常用的软件和应用都有在 Docker Hub 上提供的镜像,方便用户直接获取和使用。 例如,您想要部署一个 Nginx 服务器,就可以从 Docker Hub 上拉取 Nginx 的镜像。
  • 私有仓库则是由组织或个人自己搭建和管理的,用于存储内部使用的、不希望公开的镜像。 比如,一家企业为其特定的业务应用创建了定制化的镜像,并将其存储在自己的私有仓库中, 以保证安全性和控制访问权限。

通过 Docker 仓库,开发者能够方便地共享和复用镜像,加速应用的开发和部署过程

Docker Hub 镜像仓库-阿里云开发者社区

2、docker公有仓库

(1)官网https://hub.docker.com/进行注册登录

(2)登录信息保存位置

[root@docker-node1 ~]# cd .docker/
[root@docker-node1 .docker]# ls
buildx  config.json
[root@docker-node1 .docker]# cat config.json 
{
	"auths": {
		"https://index.docker.io/v1/": {
			"auth": "MTIzNHp4OlpYenhjdmJubQ=="
		}
	}
}[root@docker-node1 .docker]# 

(3)打标记上传docker

[root@docker-node1 ~]# docker tag webserver:v1 1234zx/webserver:v1
[root@docker-node1 ~]# docker push 1234zx/webserver:v1

3、docker仓库的工作原理

仓库中的三个角色

  • index docker索引服务,负责并维护有关用户帐户、镜像的校验以及公共命名空间的信息。
  • registry docker仓库,是镜像和图表的仓库,它不具有本地数据库以及不提供用户认证,通过Index Auth service的Token的方式进行认证
  • Registry Client Docker充当registry客户端来维护推送和拉取,以及客户端的授权。

(1)pull原理

镜像拉取分为以下几步:

  • docker客户端向index发送镜像拉去请求并完成与index的认证
  • index发送认证token和镜像位置给dockerclient
  • dockerclient携带token和根据index指引的镜像位置取连接registry
  • Registry会根据client持有的token跟index核实身份合法性
  • index确认此token合法性
  • Registry会根据client的请求传递镜像到客户端

(2)push原理

镜像上传的步骤:

  • client向index发送上传请求并完成用户认证
  • index会发方token给client来证明client的合法性
  • client携带index提供的token连接Registry
  • Registry向index合适token的合法性
  • index证实token的合法性
  • Registry开始接收客户端上传过来的镜像

4、搭建docker的私有仓库

(1)下载Registry镜像

# 直接pull下载
[root@docker-node1 ~]# docker pull registry

# 镜像导入
[root@docker-node1 ~]# docker load -i registry.tag.gz 

(2)开启Registry

[root@docker-node1 ~]# docker run -d -p 5000:5000 --restart=always --name registry registry

(3)上传镜像到仓库中

[root@docker-node1 ~]# vim /etc/docker/daemon.json 
[root@docker-node1 ~]# cat /etc/docker/daemon.json 
{
	"bip":"172.17.0.1/16",
	"registry-mirrors": ["https://y3w6d9eb.mirror.aliyuncs.com"],
	"insecure-registries" : ["http://172.25.254.100:5000"]

}

[root@docker-node1 ~]# systemctl restart docker

#给要上传的镜像打标签
[root@docker-node1 ~]# docker tag busybox:latest 172.25.254.100:5000/busybox:latest

#docker在上传的过程中默认使用https,没有建立https认证需要的认证文件会报错,故在daemon.json文件中配置非加密端口
#上传镜像
[root@docker-node1 ~]# docker push 172.25.254.100:5000/busybox:latest
The push refers to repository [172.25.254.100:5000/busybox]
d51af96cf93e: Pushed 
latest: digest: sha256:28e01ab32c9dbcbaae96cf0d5b472f22e231d9e603811857b295e61197e40a9b size: 527

# 查看镜像上传
[root@docker-node1 ~]# curl 172.25.254.100:5000/v2/_catalog
{"repositories":["busybox"]}

(4)为Registry提加密传输

将/etc/docker/daemon.json中的非加密端口去掉

[root@docker-node1 ~]# mkdir certs
[root@docker-node1 ~]# vim /etc/hosts    # 添加解析reg.zx.org <--> 172.25.254.100

#生成认证key和证书
[root@docker-node1 ~]# openssl req -newkey rsa:4096  -nodes -sha256 -keyout certs/zx.org.key \
> -addext "subjectAltName = DNS:reg.zx.org" \
> -x509 -days 365 -out certs/zx.org.crt
.+.....................+...+..+..........+........+.+............+..+...+...+......+....+............+...+..+....+........+.............+..+...+...+......+.........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.+......+.+...+..+.+.....+..........+..............+...+...+.......+...+...+......+...+...+..............+.+........+.......+..+......+............+.........+.+..+...............+.......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.+............+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.....+........+...+...+....+........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*..+.+..+..........+...+...+.....+....+.....+.......+.....+...+.+.........+.....+.+......+.....+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.............+..........+..+.+............+...+..+.........+.........+......+....+.....+....+............+........+..........+...+.....+....+..............+......+.+...+............+..+......+.+...+......+...........+.....................+...+.......+..+..........+...........+.......+..+...+.........+.+..+..................+.......+........+............+.+.................+............+.+............+...+..+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:Shaanx
Locality Name (eg, city) [Default City]:XI'an
Organization Name (eg, company) [Default Company Ltd]:docker
Organizational Unit Name (eg, section) []:registry
Common Name (eg, your name or your server's hostname) []:reg.zx.org
Email Address []:[email protected]

[root@docker-node1 ~]# ls certs/
zx.org.crt  zx.org.key
#启动registry仓库
[root@docker-node1 ~]# docker run -d -p 443:443 --restart=always --name registry -v /root/certs:/certs  -e REGISTRY_HTTP_ADDR=0.0.0.0:443 -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/zx.org.crt -e REGISTRY_HTTP_TLS_KEY=/certs/zx.org.key registry:latest

[root@docker-node1 ~]# docker ps
CONTAINER ID   IMAGE             COMMAND                  CREATED          STATUS          PORTS                                             NAMES
980cb9c0faec   registry:latest   "/entrypoint.sh /etc…"   15 seconds ago   Up 14 seconds   0.0.0.0:443->443/tcp, :::443->443/tcp, 5000/tcp   registry

测试:

[root@docker-node1 ~]# docker tag registry:latest reg.zx.org/registry:latest
[root@docker-node1 ~]# mkdir /etc/docker/certs.d/reg.zx.org/ -p
[root@docker-node1 ~]# cp /root/certs/zx.org.crt /etc/docker/certs.d/reg.zx.org/ca.crt
[root@docker-node1 ~]# systemctl restart docker
[root@docker-node1 ~]# docker push reg.zx.org/registry:latest
[root@docker-node1 ~]# curl -k https://reg.zx.org/v2/_catalog
{"repositories":["registry"]}

(5)为仓库建立登陆认证

#安装建立认证文件的工具包
[root@docker-node1 ~]# dnf install httpd-tools -y

#建立认证文件,-B 强制使用最安全加密方式,默认用md5加密
[root@docker-node1 ~]# mkdir auth
[root@docker-node1 ~]# htpasswd -Bc auth/htpasswd zx
[root@docker-node1 ~]# cat auth/htpasswd
zx:$2y$05$M0B4z68fki4VdaqIIZVDt.Md/f3aPlDXDStgjTbUX39B.X7Skdl76

#添加认证到registry容器中
[root@docker-node1 ~]# docker run -d -p 443:443 --restart=always --name registry -v /root/certs:/certs  -e REGISTRY_HTTP_ADDR=0.0.0.0:443 -e REGISTRY_HTTP_TLS_KEY=/certs/zx.org.key -v /root/auth:/auth -e REGISTRY_AUTH=htpasswd -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd registry

[root@docker-node1 ~]# docker ps
CONTAINER ID   IMAGE      COMMAND                  CREATED         STATUS         PORTS                                             NAMES
b4faa3b0ac10   registry   "/entrypoint.sh /etc…"   4 seconds ago   Up 3 seconds   0.0.0.0:443->443/tcp, :::443->443/tcp, 5000/tcp   registry

 [root@local ~]# docker login reg.zx.org    # 登录

5、构建企业级私有仓库

  • 基于角色的访问控制(RBAC):可以为不同的用户和用户组分配不同的权限,增强了安全性和管理 的灵活性。
  • 镜像复制:支持在不同的 Harbor 实例之间复制镜像,方便在多个数据中心或环境中分发镜像。
  • 图形化用户界面(UI):提供了直观的 Web 界面,便于管理镜像仓库、项目、用户等。
  • 审计日志:记录了对镜像仓库的各种操作,有助于追踪和审查活动。
  • 垃圾回收:可以清理不再使用的镜像,节省存储空间。

(1)部署harbor

[root@local ~]# mkdir /data/certs -p
[root@local ~]# cp /root/certs/ /data/ -r
[root@local certs]# ls /data/certs
zx.org.crt  zx.org.key

[root@local ~]# tar zxf harbor-offline-installer-v2.5.4.tgz
[root@local harbor]# cp harbor.yml.tmpl harbor.yml
[root@local harbor]# vim harbor.yml
    hostname: reg.zx.org
    certificate: /data/certs/zx.org.crt
    private_key: /data/certs/zx.org.key
    harbor_admin_password: 123
[root@local harbor]# ./install.sh --with-chartmuseum

#管理harbor的容器
[root@local harbor]# docker compose stop
[root@local harbor]# docker compose up -d

账号密码:admin        123

[root@docker-node1 harbor]# docker tag webserver:v1 reg.zx.org/zx/webserver:v1
[root@docker-node1 harbor]# systemctl restart docker
[root@docker-node1 harbor]# docker logout reg.zx.org
[root@docker-node1 harbor]# docker login reg.zx.org
Username: admin
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credential-stores

Login Succeeded
[root@docker-node1 harbor]# docker push reg.zx.org/zx/webserver:v1
The push refers to repository [reg.zx.org/zx/webserver]
f51abbf26a98: Pushed 
6835249f577a: Pushed 
24aacbf97031: Pushed 
8451c71f8c1e: Pushed 
2388d21e8e2b: Pushed 
c048279a7d9f: Pushed 
1a73b54f556b: Pushed 
2a92d6ac9e4f: Pushed 
bbb6cacb8c82: Pushed 
ac805962e479: Pushed 
af5aa97ebe6c: Pushed 
4d049f83d9cf: Pushed 
9ed498e122b2: Pushed 
577c8ee06f39: Pushed 
5342a2647e87: Pushed 
v1: digest: sha256:4b28e604ba45d68b34d1e337241d1182e4e75a504e440d1284275be1c990cd89 size: 3445
[root@docker-node1 harbor]# vim /etc/docker/daemon.json 
[root@docker-node1 harbor]# cat /etc/docker/daemon.json 
{
    "registry-mirrors": ["https://reg.zx.org"]
}
[root@docker-node1 harbor]# systemctl restart docker
[root@docker-node1 harbor]# docker info

(2)docker的webUI工具

[root@docker-node1 ~]# tar zxf 1panel-v1.10.13-lts-linux-amd64.tar.gz
[root@docker-node1 ~]# cd 1panel-v1.10.13-lts-linux-amd64/
[root@docker-node1 1panel-v1.10.13-lts-linux-amd64]# sh install.sh

五、Docker 网络

docker的镜像是令人称道的地方,但网络功能还是相对薄弱的部分

docker安装后会自动创建3种网络:bridge、host、none

[root@docker-node1 ~]# docker network ls
NETWORK ID     NAME                        DRIVER    SCOPE
28b770857328   1panel-network              bridge    local
419fd92d3873   bridge                      bridge    local
dc04306cd8fd   harbor_harbor               bridge    local
1c490326af48   harbor_harbor-chartmuseum   bridge    local
e5317ef5d127   host                        host      local
31b223297893   none                        null      local

1、docker原生bridge网路

docker安装时会创建一个名为 docker0 的Linux bridge,新建的容器会自动桥接到这个接口

[root@docker-node1 ~]# ip link show type bridge
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default 
    link/ether 02:42:6e:e0:17:a2 brd ff:ff:ff:ff:ff:ff

bridge模式下容器没有一个公有ip,只有宿主机可以直接访问,外部主机是不可见的。

容器通过宿主机的NAT规则后可以访问外网

# 还原默认网络配置
[root@docker-node1 ~]# cd 1panel-v1.10.13-lts-linux-amd64/
[root@docker-node1 1panel-v1.10.13-lts-linux-amd64]# 1pctl uninstall
卸载将会完全清除 1Panel 服务和数据目录,是否继续 [y/n] : y
================== 开始卸载 1Panel Linux 服务器运维管理面板 ==================

1) 停止 1Panel 服务进程...
2) 删除 1Panel 服务和数据目录...
3) 重新加载服务配置文件...

================================== 卸载完成 ==================================
[root@docker-node1 1panel-v1.10.13-lts-linux-amd64]# cd
[root@docker-node1 ~]# docker network ls
NETWORK ID     NAME                        DRIVER    SCOPE
28b770857328   1panel-network              bridge    local
d8f5b73ad49a   bridge                      bridge    local
dc04306cd8fd   harbor_harbor               bridge    local
1c490326af48   harbor_harbor-chartmuseum   bridge    local
e5317ef5d127   host                        host      local
31b223297893   none                        null      local
[root@docker-node1 ~]# 
[root@docker-node1 ~]# docker network rm 1panel-network 
[root@docker-node1 ~]# cd harbor/
[root@docker-node1 harbor]# docker compose down
[root@docker-node1 harbor]# iptables -nL        # 查看防火墙规则
[root@docker-node1 ~]# iptables -t nat -nL

 

2、docker原生网络host

host网络模式需要在容器创建时指定 --network=host host

模式可以让容器共享宿主机网络栈,这样的好处是外部主机与容器直接通信,但是容器的网络缺少 隔离性

[root@docker-node1 ~]#  docker run -it --name test --network host busybox

如果公用一个网络,那么所有的网络资源都是公用的,比如启动了nginx容器那么真实主机的80端口被占用,在启动第二个nginx容器就会失败 

3、docker 原生网络none

none模式是指禁用网络功能,只有lo接口,在容器创建时使用 --network=none指定。

[root@docker-node1 ~]#  docker run -it --name test --network none busybox

4、docker的自定义网络

自定义网络模式,docker提供了三种自定义网络驱动:

  • bridge
  • overlay
  • macvlan

bridge驱动类似默认的bridge网络模式,但增加了一些新的功能

overlay和macvlan是用于创建跨主机网络

建议使用自定义的网络来控制哪些容器可以相互通信,还可以自动DNS解析容器名称到IP地址。

为什么要自定义桥接

docker引擎在分配ip时时根据容器启动顺序分配到,谁先启动谁用,是动态变更的

多容器互访用ip很显然不是很靠谱,那么多容器访问一般使用容器的名字访问更加稳定 docker原生网络是不支持dns解析的,自定义网络中内嵌了dns

注意:不同的自定义网络是不能通讯的

(1)自定义桥接网络

[root@docker-node1 ~]# docker network create my_net1
ff1dfd524682a9b144102384040ffa54ad18b391fc4e6655e238c5d3e66ed25d
[root@docker-node1 ~]# docker network ls
NETWORK ID     NAME                        DRIVER    SCOPE
d8f5b73ad49a   bridge                      bridge    local
1c490326af48   harbor_harbor-chartmuseum   bridge    local
e5317ef5d127   host                        host      local
ff1dfd524682   my_net1                     bridge    local
31b223297893   none                        null      local

[root@docker-node1 ~]# docker run -it --name test --network bridge busybox
[root@docker-node1 ~]# docker run -it --name test0 --network bridge busybox
[root@docker-node1 ~]# docker run -it --name test1 --network my_net1 busybox
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:12:00:02  
          inet addr:172.18.0.2  Bcast:172.18.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:32 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:4716 (4.6 KiB)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ # ping -c 5 test
PING test (15.197.204.56): 56 data bytes
64 bytes from 15.197.204.56: seq=0 ttl=127 time=90.813 ms
64 bytes from 15.197.204.56: seq=1 ttl=127 time=90.716 ms
64 bytes from 15.197.204.56: seq=2 ttl=127 time=110.438 ms
64 bytes from 15.197.204.56: seq=3 ttl=127 time=93.006 ms
64 bytes from 15.197.204.56: seq=4 ttl=127 time=134.053 ms

--- test ping statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max = 90.716/103.805/134.053 ms
/ # 
/ # ping -c 5 test0
PING test0 (15.197.204.56): 56 data bytes
64 bytes from 15.197.204.56: seq=0 ttl=127 time=122.564 ms
64 bytes from 15.197.204.56: seq=1 ttl=127 time=98.731 ms
64 bytes from 15.197.204.56: seq=2 ttl=127 time=106.459 ms
64 bytes from 15.197.204.56: seq=3 ttl=127 time=308.340 ms
64 bytes from 15.197.204.56: seq=4 ttl=127 time=105.651 ms

--- test0 ping statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max = 98.731/148.349/308.340 ms
# 桥接也支持自定义子网和网关
[root@docker-node1 ~]# docker network create my_net2 --subnet 192.168.0.0/24 --gateway 192.168.0.100

(2)如何让不同的自定义网络互通?

[root@docker-node1 ~]# docker network create mynet1 -d bridge 
48671ec125476f49879ce9ae333e963c9de40a6d3ca1a9593bde4a68e39358db
[root@docker-node1 ~]# 
[root@docker-node1 ~]# docker network create mynet2 -d bridge 
c87f86f788792dc052419a7ae43babeb3ef8b531954d81b23b5f44ecbd8018da
[root@docker-node1 ~]# 
[root@docker-node1 ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
d8f5b73ad49a   bridge    bridge    local
e5317ef5d127   host      host      local
48671ec12547   mynet1    bridge    local
c87f86f78879   mynet2    bridge    local
31b223297893   none      null      local
[root@docker-node1 ~]# 
[root@docker-node1 ~]# iptables -nL

[root@docker-node1 ~]# docker run -it --name test --network mynet1 busybox
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:12:00:02  
          inet addr:172.18.0.2  Bcast:172.18.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:32 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:4716 (4.6 KiB)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)


[root@docker-node1 ~]# docker run -it --name test1 --network mynet2 busybox
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:13:00:02  
          inet addr:172.19.0.2  Bcast:172.19.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:44 errors:0 dropped:0 overruns:0 frame:0
          TX packets:7 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:6154 (6.0 KiB)  TX bytes:452 (452.0 B)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:8 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:676 (676.0 B)  TX bytes:676 (676.0 B)


[root@docker-node1 ~]# docker network connect mynet1 test1    在上面test1容器中加入网络eth1
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:13:00:02  
          inet addr:172.19.0.2  Bcast:172.19.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:47 errors:0 dropped:0 overruns:0 frame:0
          TX packets:7 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:6364 (6.2 KiB)  TX bytes:452 (452.0 B)

eth1      Link encap:Ethernet  HWaddr 02:42:AC:12:00:02  
          inet addr:172.18.0.2  Bcast:172.18.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:17 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:2318 (2.2 KiB)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:8 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:676 (676.0 B)  TX bytes:676 (676.0 B)

/ # ping -c 3 test
PING test (15.197.204.56): 56 data bytes
64 bytes from 15.197.204.56: seq=0 ttl=127 time=100.584 ms
64 bytes from 15.197.204.56: seq=1 ttl=127 time=131.775 ms
64 bytes from 15.197.204.56: seq=2 ttl=127 time=114.846 ms

--- test ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 100.584/115.735/131.775 ms

(3)joined容器网络

Joined容器一种较为特别的网络模式,在容器创建时使用--network=container:vm1指定。(vm1指定的是运行的容器名)

处于这个模式下的 Docker 容器会共享一个网络栈,这样两个容器之间可以使用localhost高效快速通信。

[root@docker-node1 ~]# docker run -it --name test --network mynet1 busybox
[root@docker-node1 ~]# docker run -it --name test1 --network container:test busybox

演示:利用容器部署phpmyadmin管理mysql
[root@docker-node1 ~]# docker load -i mysql-5.7.tar.gz 
[root@docker-node1 ~]# docker load -i phpmyadmin-latest.tar.gz

#运行phpmysqladmin
[root@docker-node1 ~]# docker run -d --name mysqladmin --network mynet1 -e PMA_ARBITRARY=1 -p 80:80 phpmyadmin:latest

#运行数据库
[root@docker-node1 ~]# docker run -d --name mysql -e MYSQL_ROOT_PASSWORD='123' --network container:mysqladmin mysql:5.7

5、容器内外网的访问

(1)容器访问外网

在rhel7中,docker访问外网是通过iptables添加地址伪装策略来完成容器网文外网

在rhel7之后的版本中通过nftables添加地址伪装来访问外网

(2)外网访问docker容器

端口映射 -p 本机端口:容器端口来暴漏端口从而达到访问效果

docker-proxy和dnat在容器建立端口映射后都会开启,那个传输速录高走那个

#通过docker-proxy对数据包进行内转
[root@docker-node1 ~]# docker run -d --name webserver -p 80:80 nginx:1.23
[root@docker-node1 ~]# ps ax
……
  11361 ?        Sl     0:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 80 -container-ip 172.17.0.2 -cont
  11367 ?        Sl     0:00 /usr/bin/docker-proxy -proto tcp -host-ip :: -host-port 80 -container-ip 172.17.0.2 -container
  11401 ?        Sl     0:00 /usr/bin/containerd-shim-runc-v2 -namespace moby -id a57ab6ad12e5d22d66f4f195b4780081b6aeb7385
  11423 ?        Ss     0:00 nginx: master process nginx -g daemon off;
  11463 ?        S      0:00 nginx: worker process
  11464 ?        S      0:00 nginx: worker process
……

[root@docker-node1 ~]# iptables -t nat -nL    # 查看策略
[root@docker-node1 ~]# docker inspect webserver    

6、docker跨主机网络

在生产环境中,容器不可能都在同一个系统中,所以需要容器具备跨主机通信的能力

  • 跨主机网络解决方案
    • docker原生的overlay和macvlan
    • 第三方的flannel、weave、calico
  • 众多网络方案是如何与docker集成在一起的
    • libnetwork docker容器网络库
    • CNM (Container Network Model)这个模型对容器网络进行了抽象

(1)CNM(Container Network Model)

CNM分三类组件

  • Sandbox:容器网络栈,包含容器接口、dns、路由表。(namespace)
  • Endpoint:作用是将sandbox接入network (veth pair)
  • Network:包含一组endpoint,同一network的endpoint可以通信

(2)macvlan网络方式实现跨主机通信

macvlan网络方式
  • Linux kernel提供的一种网卡虚拟化技术。
  • 无需Linux bridge,直接使用物理接口,性能极好
  • 容器的接口直接与主机网卡连接,无需NAT或端口映射
  • macvlan会独占主机网卡,但可以使用vlan子接口实现多macvlan网络
  • vlan可以将物理二层网络划分为4094个逻辑网络,彼此隔离,vlan id取值为1~4094
macvlan网络间的隔离和连通
  • macvlan网络在二层上是隔离的,所以不同macvlan网络的容器是不能通信的
  • 可以在三层上通过网关将macvlan网络连通起来
  • docker本身不做任何限制,像传统vlan网络那样管理即可
实现方法
1、在两台docker主机上各添加一块网卡,打开网卡混杂模式,第二块网卡 eth1 设置为仅主机模式
[root@docker-node2 ~]# ip link set eth1 promisc on
[root@docker-node2 ~]# ip link set up eth1
[root@docker-node2 ~]# ifconfig eth1
[root@docker-node1 ~]# ip link set eth1 promisc on
[root@docker-node1 ~]# ip link set up eth1
[root@docker-node1 ~]# ifconfig eth1

[root@docker-node2 ~]# docker load -i busybox-latest.tar.gz
2.添加macvlan网路
[root@docker-node1 ~]# docker network create -d macvlan --subnet 4.4.4.0/24 --gateway 4.4.4.4 -o parent=eth1 my-net1
[root@docker-node1 ~]# docker run -it --rm --name test --network my-net1 --ip 4.4.4.2 busybox

六、Docker 数据卷管理及优化

Docker 数据卷是一个可供容器使用的特殊目录,它绕过了容器的文件系统,直接将数据存储在宿主机上。

这样可以实现以下几个重要的目的:

  • 数据持久化:即使容器被删除或重新创建,数据卷中的数据仍然存在,不会丢失。
  • 数据共享:多个容器可以同时挂载同一个数据卷,实现数据的共享和交互。
  • 独立于容器生命周期:数据卷的生命周期独立于容器,不受容器的启动、停止和删除的影响。

1、为什么要用数据卷

docker分层文件系统

  • 性能差
  • 生命周期与容器相同

docker数据卷

  • mount到主机中,绕开分层文件系统
  • 和主机磁盘性能相同,容器删除后依然保留
  • 仅限本地磁盘,不能随容器迁移

docker提供了两种卷

  • bind mount
  • docker managed volume
/var/lib/docker/volumes

2、bind mount 数据卷

  • 是将主机上的目录或文件mount到容器里。
  • 使用直观高效,易于理解。
  • 使用 -v 选项指定路径,格式 :-v 选项指定的路径,如果不存在,挂载时会自动创建
[root@docker-node1 ~]# docker run -it --rm --name test -v /zx:/data1:rw -v /etc/passwd:/data2/passwd busybox
/ # ls
bin    data1  data2  dev    etc    home   lib    lib64  proc   root   sys    tmp    usr    var
/ # ls data1
zxfile1  zxfile2  zxfile3  zxfile4  zxfile5
/ # touch data1/zxfile6
/ # ls data1
zxfile1  zxfile2  zxfile3  zxfile4  zxfile5  zxfile6
/ # 
/ # ls /data2
passwd

3、docker managed 数据卷

  • bind mount必须指定host文件系统路径,限制了移植性
  • docker managed volume 不需要指定mount源,docker自动为容器创建数据卷目录
  • 默认创建的数据卷目录都在 /var/lib/docker/volumes 中
  • 如果挂载时指向容器内已有的目录,原有数据会被复制到volume中
[root@docker-node1 ~]# docker run -d --name mysql -e MYSQL_ROOT_PASSWORD='123' mysql:5.7
[root@docker-node1 ~]# docker inspect mysql

[root@docker-node1 ~]# docker volume prune    # 清理未使用的 Docker 数据卷
[root@docker-node1 ~]# docker volume create mysqldate    # 建立数据卷
[root@docker-node1 ~]# ll /var/lib/docker/volumes/mysqldate/_data/
total 0

[root@docker-node1 ~]# docker volume ls        # 查看卷
DRIVER    VOLUME NAME
local     d7ce5a61e63a342c9668a4b4bb83b9bd109bf013c244e4302c5bbf9b7c9cb4b3
local     mysqldate
[root@docker-node1 _data]# docker run -d --name mysql -e MYSQL_ROOT_PASSWORD='123' -v mysqldate:/var/lib/mysql -p 80:80 mysql:5.7
[root@docker-node1 ~]# docker inspect mysql

[root@docker-node1 ~]# cd /var/lib/docker/volumes/mysqldate/_data/
[root@docker-node1 _data]# ls
auto.cnf    client-cert.pem  ibdata1      ibtmp1      performance_schema  server-cert.pem
ca-key.pem  client-key.pem   ib_logfile0  mysql       private_key.pem     server-key.pem
ca.pem      ib_buffer_pool   ib_logfile1  mysql.sock  public_key.pem      sys
[root@docker-node1 _data]# 
[root@docker-node1 _data]# echo mysqldata > index.html
[root@docker-node1 _data]# curl 172.25.254.100

4、数据卷容器(Data Volume Container)

数据卷容器(Data Volume Container)是 Docker 中一种特殊的容器,主要用于方便地在多个容器之间共享数据卷。

(1)建立数据卷容器

[root@docker-node1 ~]# docker run -d --name datavol \
> -v /tmp/data1:/data1:rw \
> -v /tmp/data2:/data2:ro \
> -v /etc/resolv.conf:/etc/hosts busybox

(2)使用数据卷容器

[root@docker-node1 ~]# docker run -it --name test --rm --volumes-from datavol busybox
/ # ls
bin    data1  data2  dev    etc    home   lib    lib64  proc   root   sys    tmp    usr    var
/ # cat /etc/resolv.conf 
# Generated by Docker Engine.
# This file can be edited; Docker Engine will not make further changes once it
# has been modified.

nameserver 114.114.114.114
search zx.org

# Based on host file: '/etc/resolv.conf' (legacy)
# Overrides: []
/ # 
/ # touch data1/zxfile1
/ # touch data2/zxfile1
touch: data2/zxfile1: Read-only file system

5、bind mount 数据卷和docker managed 数据卷的对比

(1)相同点:

        两者都是 host 文件系统中的某个路径

(2)不同点:

bind mountdocker managed volume
volume 位置可任意指定/var/lib/docker/volumes/...
对已有mount point影响隐藏并替换为volume原有数据复制到volume
是否支持单个位置支持不支持,只能是目录
权限控制可设置为只读,默认为读写权限无控制,均为读写权限
移植性移植性弱,与host path绑定移植性强,无需指定host目录

6、备份与迁移数据卷

(1)备份数据卷

#建立容器并指定使用卷到要备份的容器
[root@docker-node1 ~]# docker run -d --name datavol -v /tmp/data1:/data1:rw -v /tmp/data2:/data2:ro -v /etc/resolv.conf:/etc/hosts busybox

#把当前目录挂在到容器中用于和容器交互保存要备份的容器,备份数据到本地
[root@docker-node1 ~]# docker run --volumes-from datavol \
> -v `pwd`:/backup busybox \
> tar zcf /backup/data1.tar.gz /data1

(2)数据恢复

#数据恢复
[root@docker-node1 ~]# docker run -it --name test -v zxvol1:/data1 -v `pwd`:/backup busybox /bin/sh -c "tar zxf /backup/data1.tar.gz;/bin/sh"
/ # ls
backup  data1   etc     lib     proc    sys     usr
bin     dev     home    lib64   root    tmp     var
/ # cd data1/
/data1 # ls
zxfile1
/data1 # 

七、Docker 的安全优化

Docker容器的安全性,很大程度上依赖于Linux系统自身

评估Docker的安全性时,主要考虑以下几个方面:

  • Linux内核的命名空间机制提供的容器隔离安全
  • Linux控制组机制对容器资源的控制能力安全
  • Linux内核的能力机制所带来的操作权限安全
  • Docker程序(特别是服务端)本身的抗攻击性
  • 其他安全增强机制对容器安全性的影响
#在rhel9中默认使用cgroup-v2 但是cgroup-v2中不利于观察docker的资源限制情况,所以推荐使用cgroup-v1
[root@docker-node1 cgroup]# grubby --update-kernel=/boot/vmlinuz-$(uname -r) \
> --args="systemd.unified_cgroup_hierarchy=0 \
> systemd.legacy_systemd_cgroup_controller"

或者
sudo grubby --update-kernel=ALL --args="systemd.unified_cgroup_hierarchy=1"

命名空间隔离的安全

  • 当docker run启动一个容器时,Docker将在后台为容器创建一个独立的命名空间。命名空间提供了 最基础也最直接的隔离。
  • 与虚拟机方式相比,通过Linux namespace来实现的隔离不是那么彻底。
  • 容器只是运行在宿主机上的一种特殊的进程,那么多个容器之间使用的就还是同一个宿主机的操作 系统内核。
  • 在 Linux 内核中,有很多资源和对象是不能被 Namespace 化的,比如:磁盘等等

控制组资源控制的安全

  • 当docker run启动一个容器时,Docker将在后台为容器创建一个独立的控制组策略集合。
  • Linux Cgroups提供了很多有用的特性,确保各容器可以公平地分享主机的内存、CPU、磁盘IO等资源。
  • 确保当发生在容器内的资源压力不会影响到本地主机系统和其他容器,它在防止拒绝服务攻击 (DDoS)方面必不可少
#内存资源默认没有被隔离
[root@docker-node1 ~]# docker run -it --name test busybox
/ # free -m
              total        used        free      shared  buff/cache   available
Mem:           1751         519         199          10        1033        1054
Swap:          2072          16        2056
/ # exit
[root@docker-node1 ~]# free -m
               total        used        free      shared  buff/cache   available
Mem:            1750         651         243          10        1032        1098
Swap:           2071          15        2056

内核能力机制

  • 能力机制(Capability)是Linux内核一个强大的特性,可以提供细粒度的权限访问控制。
  • 大部分情况下,容器并不需要“真正的”root权限,容器只需要少数的能力即可。
  • 默认情况下,Docker采用“白名单”机制,禁用“必需功能”之外的其他权限。

Docker服务端防护

  • 使用Docker容器的核心是Docker服务端,确保只有可信的用户才能访问到Docker服务。
  • 将容器的root用户映射到本地主机上的非root用户,减轻容器和主机之间因权限提升而引起的安全 问题。
  • 允许Docker 服务端在非root权限下运行,利用安全可靠的子进程来代理执行需要特权权限的操作。 这些子进程只允许在特定范围内进行操作。
#默认docker是用root用户控制资源的
[root@docker-node1 ~]#  ls -ld /var/lib/docker/
drwx--x--- 12 root root 171 Aug 30 20:39 /var/lib/docker/

1、Docker的资源限制

Linux Cgroups 的全称是 Linux Control Group。

  • 是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等。
  • 对进程进行优先级设置、审计,以及将进程挂起和恢复等操作。

Linux Cgroups 给用户暴露出来的操作接口是文件系统

  • 它以文件和目录的方式组织在操作系统的 /sys/fs/cgroup 路径下。
  • 执行此命令查看:mount -t cgroup
  • 在 /sys/fs/cgroup 下面有很多诸如 cpuset、cpu、 memory 这样的子目录,也叫子系统。
  • 在每个子系统下面,为每个容器创建一个控制组(即创建一个新目录)。
  • 控制组下面的资源文件里填上什么值,就靠用户执行 docker run 时的参数指定。
[root@docker-node1 ~]# mount -t cgroup
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,name=systemd)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/misc type cgroup (rw,nosuid,nodev,noexec,relatime,misc)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
[root@docker-node1 ~]# 

(1)限制CPU使用

[root@docker-node1 ~]# docker load -i ubuntu-latest.tar.gz 
#设置 CPU 周期的长度,单位为微秒(通常为100000,即 100 毫秒)
#设置容器在一个周期内可以使用的 CPU 时间,单位也是微秒。
[root@docker-node1 ~]# docker run -it --name test1 --rm --cpu-period 10000 --cpu-quota 20000 ubuntu
root@38f21bdd925b:/#  dd if=/dev/zero of=/dev/null &
[1] 9
root@38f21bdd925b:/# top

#在cgroup中查看docker的资源限制
[root@docker-node1 ~]# cat /sys/fs/cgroup/system.slice/docker-38f21bdd925b8a1b269a085168a579c43c37e80b0501d8473b7a5c5dc1a9e53e.scope/cpu.max
20000 10000

(2)限制CPU的优先级

#关闭cpu的核心,当cpu都不空闲下才会出现争抢的情况,为了实验效果关闭一个cpu核心
[root@docker-node1 ~]# echo 0 > /sys/devices/system/cpu/cpu1/online        # 限制为单核
[root@docker-node1 ~]# cat /proc/cpuinfo

# 单核下
[root@docker-node1 ~]# docker run -it --rm --cpu-shares 100 ubuntu
root@dea27188a3ff:/# dd if=/dev/zero of=/dev/null &

# 双核下
[root@docker-node2 ~]# docker load -i ubuntu-latest.tar.gz 
f36fd4bb7334: Loading layer  80.56MB/80.56MB
Loaded image: ubuntu:latest
[root@docker-node2 ~]# 
[root@docker-node2 ~]# docker run -it --rm --cpu-shares 100 ubuntu
root@0569400ae98d:/# dd if=/dev/zero of=/dev/null &
[1] 9
root@0569400ae98d:/# top

在单核下明显看到CPU的使用被限制到,双核下未被限制住CPU的使用,但CPU的优先级两者皆能明显看到效果——在首行

(3)限制内存使用

[root@docker-node1 ~]# docker run --name test -it --memory 200M --memory-swap 200M ubuntu

[root@docker-node1 ~]# cd /sys/fs/cgroup/memory/docker/
[root@docker-node1 docker]# cd b2e88d44be7d526be64f49f0d90189bacb813b4aed2dfb5b1aba8368ae48ea0c/
[root@docker-node1 b2e88d44be7d526be64f49f0d90189bacb813b4aed2dfb5b1aba8368ae48ea0c]# cat memory.limit_in_bytes 
209715200
[root@docker-node1 b2e88d44be7d526be64f49f0d90189bacb813b4aed2dfb5b1aba8368ae48ea0c]# cat memory.memsw.limit_in_bytes 
209715200
法一

测试容器内存限制,在容器中我们测试内存限制效果不是很明显,可以利用工具模拟容器在内存中写入数据,在系统中/dev/shm这个目录被挂在到内存中

cgexec -g memory:doceker/容器id -g表示使用指定控制器类型

[root@docker-node1 ~]# dnf install libcgroup-0.41-19.el8.x86_64.rpm  -y
[root@docker-node1 ~]# dnf install libcgroup-tools-0.41-19.el8.x86_64.rpm -y

[root@docker-node1 ~]# docker run --name test -it --memory 200M --memory-swap 200M ubuntu
[root@docker-node1 docker]# cgexec -g memory:docker/8bc9895a1f6fd846293945c23e470c9ff4c2dd3c74b17ce2b14f33a8e6a7ebdd/ dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 0.111329 s, 942 MB/s
[root@docker-node1 docker]# 
[root@docker-node1 docker]# cgexec -g memory:docker/8bc9895a1f6fd846293945c23e470c9ff4c2dd3c74b17ce2b14f33a8e6a7ebdd/ dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=150
150+0 records in
150+0 records out
157286400 bytes (157 MB, 150 MiB) copied, 0.116302 s, 1.4 GB/s
[root@docker-node1 docker]# cgexec -g memory:docker/8bc9895a1f6fd846293945c23e470c9ff4c2dd3c74b17ce2b14f33a8e6a7ebdd/ dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=200
Killed

法二:自建控制器
[root@docker-node1 ~]# cd /sys/fs/cgroup/memory/
[root@docker-node1 memory]# 
[root@docker-node1 memory]# ls
cgroup.clone_children           memory.kmem.tcp.limit_in_bytes      memory.soft_limit_in_bytes
cgroup.event_control            memory.kmem.tcp.max_usage_in_bytes  memory.stat
cgroup.procs                    memory.kmem.tcp.usage_in_bytes      memory.swappiness
cgroup.sane_behavior            memory.kmem.usage_in_bytes          memory.usage_in_bytes
dev-hugepages.mount             memory.limit_in_bytes               memory.use_hierarchy
dev-mqueue.mount                memory.max_usage_in_bytes           notify_on_release
docker                          memory.memsw.failcnt                release_agent
memory.failcnt                  memory.memsw.limit_in_bytes         sys-fs-fuse-connections.mount
memory.force_empty              memory.memsw.max_usage_in_bytes     sys-kernel-config.mount
memory.kmem.failcnt             memory.memsw.usage_in_bytes         sys-kernel-debug.mount
memory.kmem.limit_in_bytes      memory.move_charge_at_immigrate     sys-kernel-tracing.mount
memory.kmem.max_usage_in_bytes  memory.numa_stat                    system.slice
memory.kmem.slabinfo            memory.oom_control                  tasks
memory.kmem.tcp.failcnt         memory.pressure_level               user.slice
[root@docker-node1 memory]# mkdir x1
[root@docker-node1 memory]# cd x1/
[root@docker-node1 x1]# ls
cgroup.clone_children           memory.kmem.tcp.max_usage_in_bytes  memory.oom_control
cgroup.event_control            memory.kmem.tcp.usage_in_bytes      memory.pressure_level
cgroup.procs                    memory.kmem.usage_in_bytes          memory.soft_limit_in_bytes
memory.failcnt                  memory.limit_in_bytes               memory.stat
memory.force_empty              memory.max_usage_in_bytes           memory.swappiness
memory.kmem.failcnt             memory.memsw.failcnt                memory.usage_in_bytes
memory.kmem.limit_in_bytes      memory.memsw.limit_in_bytes         memory.use_hierarchy
memory.kmem.max_usage_in_bytes  memory.memsw.max_usage_in_bytes     notify_on_release
memory.kmem.slabinfo            memory.memsw.usage_in_bytes         tasks
memory.kmem.tcp.failcnt         memory.move_charge_at_immigrate
memory.kmem.tcp.limit_in_bytes  memory.numa_stat

#内存可用大小限制
[root@docker-node1 x1]# echo 209715200 > /sys/fs/cgroup/memory/x1/memory.limit_in_bytes
#此控制器被那个进程调用
[root@docker-node1 x1]# cat /sys/fs/cgroup/memory/x1/tasks
[root@docker-node1 x1]# cgexec -g memory:x1 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 0.0869935 s, 1.2 GB/s
[root@docker-node1 x1]# free -m
               total        used        free      shared  buff/cache   available
Mem:            1750         685         451         107         874        1065
Swap:           2071           0        2071

[root@docker-node1 x1]# cgexec -g memory:x1 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=300
300+0 records in
300+0 records out
314572800 bytes (315 MB, 300 MiB) copied, 0.771034 s, 408 MB/s
[root@docker-node1 x1]# free -m
               total        used        free      shared  buff/cache   available
Mem:            1750         783         353         184         953         967
Swap:           2071         122        1949
#内存溢出部分被写入swap交换分区


[root@docker-node1 ~]# rm -fr /dev/shm/bigfile
[root@docker-node1 ~]# echo 209715200 > /sys/fs/cgroup/memory/x1/memory.memsw.limit_in_bytes    #内存+swap控制
[root@docker-node1 ~]# cgexec -g memory:x1 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=200
Killed
[root@docker-node1 ~]# cgexec -g memory:x1 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=199
Killed
[root@docker-node1 ~]# cgexec -g memory:x1 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=190
190+0 records in
190+0 records out
199229440 bytes (199 MB, 190 MiB) copied, 0.133858 s, 1.5 GB/s

(4)限制docker的磁盘io

[root@docker-node1 ~]# docker run -it --rm --device-write-bps /dev/nvme0n1:30M ubuntu
root@d61e5f1cc529:/#  dd if=/dev/zero of=bigfile

^C19831485+0 records in
19831485+0 records out
10153720320 bytes (10 GB, 9.5 GiB) copied, 59.5736 s, 170 MB/s

root@d61e5f1cc529:/# dd if=/dev/zero of=bigfile bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 0.101623 s, 1.0 GB/s
root@d61e5f1cc529:/# 
root@d61e5f1cc529:/# dd if=/dev/zero of=bigfile bs=1M count=100 oflag=direct
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 3.33883 s, 31.4 MB/s

2、Docker的安全加固

(1)Docker默认隔离性

在系统中运行容器,我们会发现资源并没有完全隔离开

虽然限制了容器的内容使用情况,但是查看到的信息依然是系统中内存的使用信息,并没有隔离开

(2)解决Docker的默认隔离性

LXCFS 是一个为 LXC(Linux Containers)容器提供增强文件系统功能的工具。

主要功能

1. 资源可见性: LXCFS 可以使容器内的进程看到准确的 CPU、内存和磁盘 I/O 等资源使用信息。在没有 LXCFS 时,容器内看到的资源信息可能不准确,这会影响到在容器内运行的应用程序对资源的评估和 管理。

2. 性能监控: 方便对容器内的资源使用情况进行监控和性能分析。通过提供准确的资源信息,管理员和开发 人员可以更好地了解容器化应用的性能瓶颈,并进行相应的优化。

# 安装lxcfs
[root@docker-node1 ~]# mkdir lxc
[root@docker-node1 ~]# cd lxc
[root@docker-node1 lxc]# ls
lxcfs-5.0.4-1.el9.x86_64.rpm  lxc-libs-4.0.12-1.el9.x86_64.rpm  lxc-templates-4.0.12-1.el9.x86_64.rpm
[root@docker-node1 lxc]# dnf install *.rpm -y

# 运行lxcfs并解决容器隔离性
[root@docker-node1 ~]# lxcfs /var/lib/lxcfs &        # 打入后台运行
[1] 6082

[root@docker-node1 ~]# ps ax
……
   6082 pts/0    Sl     0:00 lxcfs /var/lib/lxcfs
……

[root@docker-node1 ~]# cd /var/lib/lxcfs/
[root@docker-node1 lxcfs]# ls
cgroup  proc  sys

[root@docker-node1 ~]# docker run -it -m 256m --name test \
> -v /var/lib/lxcfs/proc/cpuinfo:/proc/cpuinfo:rw \
> -v /var/lib/lxcfs/proc/diskstats:/proc/diskstats:rw \
> -v /var/lib/lxcfs/proc/meminfo:/proc/meminfo:rw \
> -v /var/lib/lxcfs/proc/stat:/proc/stat:rw \
> -v /var/lib/lxcfs/proc/swaps:/proc/swaps:rw \
> -v /var/lib/lxcfs/proc/uptime:/proc/uptime:rw \
> ubuntu

(3)容器特权

在容器中默认情况下即使我是容器的超级用户也无法修改某些系统设定,比如网络

[root@docker-node1 ~]# 
[root@docker-node1 ~]# docker run --rm -it busybox
/ # 
/ # 
/ # whoami
root
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
33: eth0@if34: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
/ # 
/ # ip addr add 192.168.0.100/24 dev eth0
ip: RTNETLINK answers: Operation not permitted        # 不允许添加

这是因为容器使用的很多资源都是和系统真实主机公用的,如果允许容器修改这些重要资源,系统的稳定性会变的非常差

但是由于某些需要求,容器需要控制一些默认控制不了的资源,如何解决此问题,这时我们就要设置容器特权

[root@docker-node1 ~]# docker run --rm -it --privileged busybox

(4)容器特权的白名单

--privileged=true 的权限非常大,接近于宿主机的权限,为了防止用户的滥用,需要增加限制,只提供给容器必须的权限。此时Docker 提供了权限白名单的机制,使用--cap-add添加必要的权限

#限制容器对网络有root权限
[root@docker-node1 ~]# docker run --rm -it --cap-add NET_ADMIN busybox

八、容器编排工具Docker Compose

1、Docker Compose 概述

Docker Compose 是一个用于定义和运行多容器 Docker 应用程序的工具。 其是官方的一个开源项目,托管到github上

主要功能

1. 定义服务

使用 YAML 格式的配置文件来定义一组相关的容器服务。每个服务可以指定镜像、端口映射、 环境变量、存储卷等参数。

例如,可以在配置文件中定义一个 Web 服务和一个数据库服务,以及它们之间的连接关系。

2. 一键启动和停止

通过一个简单的命令,可以启动或停止整个应用程序所包含的所有容器。这大大简化了多容器应用的部署和管理过程。 例如,使用 docker-compose up 命令可以启动配置文件中定义的所有服务,使用 dockercompose down 命令可以停止并删除这些服务。

3. 服务编排

可以定义容器之间的依赖关系,确保服务按照正确的顺序启动和停止。例如,可以指定数据库服务必须在 Web 服务之前启动。

支持网络配置,使不同服务的容器可以相互通信。可以定义一个自定义的网络,将所有相关的容器连接到这个网络上。

4. 环境变量管理

可以在配置文件中定义环境变量,并在容器启动时传递给容器。这使得在不同环境(如开发、 测试和生产环境)中使用不同的配置变得更加容易。 例如,可以定义一个数据库连接字符串的环境变量,在不同环境中可以设置不同的值。

Docker Compose 中的管理层

1. 服务 (service) 一个应用的容器,实际上可以包括若干运行相同镜像的容器实例

2. 项目 (project) 由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义

3. 容器(container)容器是服务的具体实例,每个服务可以有一个或多个容器。容器是基于服务定义的镜像创建的运行实例

工作原理

  • 读取配置文件: Docker Compose 读取 YAML 配置文件,解析其中定义的服务和参数。
  • 创建容器: 根据配置文件中的定义,Docker Compose 调用 Docker 引擎创建相应的容器。它会下载所需 的镜像(如果本地没有),并设置容器的各种参数。
  • 管理容器生命周期: Docker Compose 监控容器的状态,并在需要时启动、停止、重启容器。 它还可以处理容器的故障恢复,例如自动重启失败的容器。

2、Docker Compose 的常用命令参数

[root@docker-node1 ~]# vim ~/.vimrc
[root@docker-node1 ~]# cat ~/.vimrc
set ts=2 sw=2 ai et

[root@docker-node1 ~]# mkdir test
[root@docker-node1 test]# vim docker-compose.yml
[root@docker-node1 test]# cat docker-compose.yml 
services:
  web:
    image: nginx:latest
    ports:
      - "80:80"

  testnode:
    image: busybox:latest
    command: ["/bin/sh","-c","sleep 100000"]

(1)服务管理

docker compose up
  • 启动配置文件中定义的所有服务。
  • 可以使用 -d 参数在后台启动服务。
  • 可以使用-f 来指定yml文件
[root@docker-node1 test]# docker compose up -d
[+] Running 3/3
 ✔ Network test_default       Created                                                                          0.3s 
 ✔ Container test-web-1       Started                                                                          1.4s 
 ✔ Container test-testnode-1  Started                                                                          1.4s 
[root@docker-node1 test]# docker ps -a
CONTAINER ID   IMAGE            COMMAND                  CREATED              STATUS              PORTS                               NAMES
bcbe4e548443   busybox:latest   "/bin/sh -c 'sleep 1…"   About a minute ago   Up About a minute                                       test-testnode-1
9fa44d75189b   nginx:latest     "/docker-entrypoint.…"   About a minute ago   Up About a minute   0.0.0.0:80->80/tcp, :::80->80/tcp   test-web-1


[root@docker-node1 ~]# docker compose -f test/docker-compose.yml up -d
[+] Running 2/2
 ✔ Container test-web-1       Started                                                                                           0.9s 
 ✔ Container test-testnode-1  Started                                                                                           0.7s 
[root@docker-node1 ~]# 
[root@docker-node1 ~]# docker ps -a
CONTAINER ID   IMAGE            COMMAND                  CREATED         STATUS         PORTS                               NAMES
8cfe11057ac7   nginx:latest     "/docker-entrypoint.…"   9 seconds ago   Up 8 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp   test-web-1
280c8288c6ac   busybox:latest   "/bin/sh -c 'sleep 1…"   9 seconds ago   Up 8 seconds                                       test-testnode-1

docker compose down

停止并删除配置文件中定义的所有服务以及相关的网络和存储卷。

[root@docker-node1 test]# docker compose down
[+] Running 3/3
 ✔ Container test-testnode-1  Removed                                                                                                10.3s 
 ✔ Container test-web-1       Removed                                                                                                 0.2s 
 ✔ Network test_default       Removed                                                                                                 0.2s 

docker compose start

启动已经存在的服务,但不会创建新的服务。

[root@docker-node1 test]# docker compose start

docker compose stop
[root@docker-node1 test]# docker compose stop

docker compose restart
[root@docker-node1 test]# docker ps -a

(2)服务状态查看

docker compose ps

列出正在运行的服务以及它们的状态,包括容器 ID、名称、端口映射等信息。

[root@docker-node1 test]# docker compose ps
NAME              IMAGE            COMMAND                  SERVICE    CREATED         STATUS              PORTS
test-testnode-1   busybox:latest   "/bin/sh -c 'sleep 1…"   testnode   5 minutes ago   Up About a minute   
test-web-1        nginx:latest     "/docker-entrypoint.…"   web        5 minutes ago   Up About a minute   0.0.0.0:80->80/tcp, :::80->80/tcp

docker compose logs 

查看服务的日志输出。可以指定服务名称来查看特定服务的日志。

[root@docker-node1 test]# docker compose logs web

(3)构建和重新构建服务

docker-compose build

构建配置文件中定义的服务的镜像。可以指定服务名称来只构建特定的服务。

[root@docker-node1 ~]# mkdir -p /root/docker
[root@docker-node1 ~]# cd /root/docker/
[root@docker-node1 docker]# vim Dockerfile
[root@docker-node1 docker]# vim zx

[root@docker-node1 docker]# cat Dockerfile 
FROM busybox:latest
RUN touch /zxfile1
[root@docker-node1 docker]# cat zx
FROM busybox:latest
RUN touch /zxfile2

[root@docker-node1 ~]# cd /root/test/
[root@docker-node1 test]# ls
docker-compose.yml
[root@docker-node1 test]# vim docker-compose.yml 
[root@docker-node1 test]# cat docker-compose.yml 
services:
  test1:
    image: test1
    build:
      context: /root/docker
      dockerfile: Dockerfile
    command: ["/bin/sh","-c","sleep 3000"]
    restart: always
    container_name: zx1

  test2:
    image: test2
    build:
      context: /root/docker
      dockerfile: zx
    command: ["/bin/sh","-c","sleep 3000"]
    restart: always
    container_name: zx2
[root@docker-node1 test]# docker compose up -d    #构建services中的所有

[root@docker-node1 test]# docker compose build test1    #构建services中的test1

docker compose up --build

启动服务并在启动前重新构建镜像

[root@docker-node1 test]# docker compose up            #会去仓库拉去镜像
[root@docker-node1 test]# docker compose up --build    #会先构建镜像后启动容器

(4)其他操作

docker-compose exec

在正在运行的服务容器中执行命令

[root@docker-node1 test]# docker compose up -d
[root@docker-node1 test]# docker ps -a
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS          PORTS     NAMES
776e0e93f6b7   test1     "/bin/sh -c 'sleep 3…"   4 minutes ago   Up 39 seconds             zx1
e10db596eebf   test2     "/bin/sh -c 'sleep 3…"   4 minutes ago   Up 39 seconds             zx2

[root@docker-node1 test]# docker compose exec test1 sh

docker-compose pull

拉取配置文件中定义的服务所使用的镜像。

[root@docker-node1 test]# docker compose pull    # 不运行,只拉取镜像

 

docker-compose config
[root@docker-node1 test]# docker compose config
[root@docker-node1 test]# docker compose config -q

 

3、Docker Compose 的yml文件

Docker Compose 的 YAML 文件用于定义和配置多容器应用程序的各个服务。

以下是一个基本的 Docker Compose YAML 文件结构及内容解释:

(1)服务

服务名称(service1_name/service2_name 等)

每个服务在配置文件中都有一个唯一的名称,用于在命令行和其他部分引用该服务

services:
    web:
        # 服务1的配置
    mysql:
        # 服务2的配置

镜像(image)

指定服务所使用的 Docker 镜像名称和标签。

例如, image: nginx:latest 表示使用 nginx 镜像的最新版本

services:
    web:
        images:nginx
    mysql:
        images:mysql:5.7

端口映射

将容器内部的端口映射到主机的端口,以便外部可以访问容器内的服务。例如, - "8080:80" 表示将主机的 8080 端口映射到容器内部的 80 端口。

[root@docker-node1 test]# cat docker-compose.yml 
services:
  test1:
    image: test1
    build:
      context: /root/docker
      dockerfile: Dockerfile
    command: ["/bin/sh","-c","sleep 3000"]
    restart: always
    container_name: zx1
    expose:
      - 1234

[root@docker-node1 test]# cat docker-compose.yml 
services:
  test1:
    image: nginx
    container_name: webserver
    ports:
      - "80:8080"

环境变量(environment)

为容器设置环境变量,可以在容器内部的应用程序中使用。

例如, VAR1: value1 设置环境变 量 VAR1 的值为 value1

[root@docker-node1 test]# vim docker-compose.yml 
[root@docker-node1 test]# cat docker-compose.yml 
services:
  test1:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: 123

[root@docker-node1 test]# docker compose up -d
[+] Running 2/2
 ? Network test_default    Created                                                                                                     0.2s 
 ? Container test-test1-1  Started                                                                                                     1.0s 
[root@docker-node1 test]# docker ps
CONTAINER ID   IMAGE       COMMAND                  CREATED         STATUS         PORTS                 NAMES
ff2ece17fbba   mysql:5.7   "docker-entrypoint.s…"   8 seconds ago   Up 7 seconds   3306/tcp, 33060/tcp   test-test1-1
[root@docker-node1 test]# 
[root@docker-node1 test]# docker inspect test-test1-1 

存储卷(volumes)

 将主机上的目录或文件挂载到容器中,以实现数据持久化或共享。

例如, - /host/data:/container/data 将主机上的 /host/data 目录挂载到容器内的 /container/data 路径

[root@docker-node1 test]# vim docker-compose.yml 
[root@docker-node1 test]# docker compose up -d
[+] Running 2/2
 ✔ Network test_default    Created                                                                                                     0.3s 
 ✔ Container test-test1-1  Started                                                                                                     0.8s 
[root@docker-node1 test]# cat docker-compose.yml 
services:
  test1:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: 123
    volumes:  
      - /opt/mysql_data:/var/lib/mysql
[root@docker-node1 test]# docker inspect test-test1-1

网络(networks)

 将服务连接到特定的网络,以便不同服务的容器可以相互通信

root@docker-node1 ~]# cd test/
[root@docker-node1 test]# docker compose down
[+] Running 2/2
 ? Container test-test1-1  Removed                                                                                                     2.2s 
 ? Network test_default    Removed                                                                                                     0.2s 
[root@docker-node1 test]# 
[root@docker-node1 test]# vim docker-compose.yml 
[root@docker-node1 test]# docker compose up -d
[+] Running 2/2
 ? Network test_default  Created                                                                                                       0.3s 
 ? Container zx          Started                                                                                                       0.7s 
[root@docker-node1 test]# docker network ls
NETWORK ID     NAME           DRIVER    SCOPE
2ee0d242a5d0   bridge         bridge    local
e5317ef5d127   host           host      local
31b223297893   none           null      local
93e724548860   test_default   bridge    local
[root@docker-node1 test]# cat docker-compose.yml 
services:
  test1:
    image: busybox:latest
    container_name: zx
    command: ["/bin/sh","-c","sleep100000"]

#使用本机自带bridge网络
[root@docker-node1 test]# vim docker-compose.yml 
[root@docker-node1 test]# cat docker-compose.yml 
services:
  test1:
    image: busybox:latest
    container_name: zx
    command: ["/bin/sh","-c","sleep100000"]
    network_mode: bridge

[root@docker-node1 test]# docker compose up -d
[+] Running 1/1
 ✔ Container zx  Started                                                                                                               0.6s 
[root@docker-node1 test]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
2ee0d242a5d0   bridge    bridge    local
e5317ef5d127   host      host      local
31b223297893   none      null      local
[root@docker-node1 test]# vim docker-compose.yml 
[root@docker-node1 test]# cat docker-compose.yml 
services:
  test1:
    image: busybox:latest
    container_name: zx
    command: ["/bin/sh","-c","sleep100000"]
    network_mode: none

[root@docker-node1 test]# docker compose up -d
[+] Running 1/1
 ✔ Container zx  Started                                                                                                               0.5s 
[root@docker-node1 test]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
2ee0d242a5d0   bridge    bridge    local
e5317ef5d127   host      host      local
31b223297893   none      null      local
# 自建网络
[root@docker-node1 test]# vim docker-compose.yml 
[root@docker-node1 test]# docker compose up -d
[+] Running 3/3
 ✔ Network test_mynet1  Created                                                                                                       0.3s 
 ✔ Network test_mynet2  Created                                                                                                       0.2s 
 ✔ Container zx         Started                                                                                                       0.7s 
[root@docker-node1 test]# docker network ls
NETWORK ID     NAME          DRIVER    SCOPE
2ee0d242a5d0   bridge        bridge    local
e5317ef5d127   host          host      local
31b223297893   none          null      local
97033aa95bfc   test_mynet1   bridge    local
06cbdbd6a62f   test_mynet2   bridge    local
[root@docker-node1 test]# cat docker-compose.yml 
services:
  test1:
    image: busybox:latest
    container_name: zx
    command: ["/bin/sh","-c","sleep100000"]
    networks:
      - mynet1
      - mynet2

networks:
  mynet1:
    driver: bridge

  mynet2:
    driver: bridge

命令(command)

覆盖容器启动时默认执行的命令。例如, command: python app.py 指定容器启动时运行 python app.py 命令

[root@docker-node1 test]# cat docker-compose.yml 
services:
  test1:
    image: busybox:latest
    container_name: zx
    command: ["/bin/sh","-c","sleep100000"]

 

(2)网络(networks)

  • 定义 Docker Compose 应用程序中使用的网络。可以自定义网络名称和驱动程序等属性。
  • 默认情况下docker compose 在执行时会自动建立网路
#不建立新的网络而使用外部资源
[root@docker-node1 test]# docker compose down
[+] Running 3/3
 ✔ Container zx         Removed                                                                                                       0.0s 
 ✔ Network test_mynet1  Removed                                                                                                       0.2s 
 ✔ Network test_mynet2  Removed                                                                                                       0.4s 
[root@docker-node1 test]# 
[root@docker-node1 test]# vim docker-compose.yml 
[root@docker-node1 test]# docker compose up -d
[+] Running 1/1
 ✔ Container test  Started                                                                                                            0.6s 
[root@docker-node1 test]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
2ee0d242a5d0   bridge    bridge    local
e5317ef5d127   host      host      local
31b223297893   none      null      local
[root@docker-node1 test]# cat docker-compose.yml 
services:
  test:
    image: busybox:latest
    container_name: test
    command: ["/bin/sh","-c","sleep 10000"]
    network_mode: default
networks:
  default:
    external: true      #不建立新的网络而使用外部资源
    name: bridge        #指定外部资源网络名字

[root@docker-node1 test]# docker compose down
[+] Running 1/1
 ? Container test  Removed                                                                                                           10.3s 
[root@docker-node1 test]# vim docker-compose.yml 
[root@docker-node1 test]# docker compose up -d
[+] Running 3/3
 ? Network test_mynet1  Created                                                                                                       0.3s 
 ? Container test2      Started                                                                                                       0.8s 
 ? Container test       Started                                                                                                       0.8s 
[root@docker-node1 test]# cat docker-compose.yml 
services:
  test:
    image: busybox:latest
    container_name: test
    command: ["/bin/sh","-c","sleep 10000"]
    network_mode: default
  test2:
    image: busybox:latest
    container_name: test2
    command: ["/bin/sh","-c","sleep 10000"]
    networks:
      - mynet1

networks:
  default:
    external: true
    name: bridge

  mynet1:
    driver: bridge
[root@docker-node1 test]# docker network ls
NETWORK ID     NAME          DRIVER    SCOPE
2ee0d242a5d0   bridge        bridge    local
e5317ef5d127   host          host      local
31b223297893   none          null      local
334b5038cf75   test_mynet1   bridge    local

[root@docker-node1 test]# vim docker-compose.yml 
[root@docker-node1 test]# docker compose up -d
[+] Running 3/3
 ? Network test_mynet2  Created                     
 ? Container test2      Started                     
 ? Container test       Started                     
[root@docker-node1 test]# docker network ls
NETWORK ID     NAME          DRIVER    SCOPE
2ee0d242a5d0   bridge        bridge    local
e5317ef5d127   host          host      local
31b223297893   none          null      local
a7fa4f01b875   test_mynet1   bridge    local
8b6e852c9552   test_mynet2   bridge    local
[root@docker-node1 test]# cat docker-compose.yml 
services:
  test:
    image: busybox:latest
    container_name: test
    command: ["/bin/sh","-c","sleep 10000"]
    network_mode: default
  test2:
    image: busybox:latest
    container_name: test2
    command: ["/bin/sh","-c","sleep 10000"]
    networks:
      - mynet1
      - mynet2

networks:
  default:
    external: true
    name: bridge

  mynet1:
    driver: bridge

  mynet2:
    ipam:
      driver: default
      config:
        - subnet: 172.26.0.0/24
          gateway: 172.26.0.254

[root@docker-node1 ~]# docker exec -it test2 sh
/ # ifconfig
/ # route -n

3、存储卷

定义 Docker Compose 应用程序中使用的存储卷。可以自定义卷名称和存储位置等属性。

[root@docker-node1 test]# vim docker-compose.yml 
[root@docker-node1 test]# docker compose up -d
[+] Running 3/3
 ✔ Volume "zx"      Created                   0.0s 
 ✔ Container test   Runni...                  0.0s 
 ✔ Container test2  Star...                  11.0s 
[root@docker-node1 test]# docker inspect test2

[root@docker-node1 test]# docker exec -it test2 sh
/ # ls
bin    dev    home   lib64  root   tmp    var
data   etc    lib    proc   sys    usr
/ # cd data/
/data # touch file
/data # exit
[root@docker-node1 test]# docker compose down
[root@docker-node1 ~]# cd /var/lib/docker/
[root@docker-node1 docker]# cd volumes/
[root@docker-node1 volumes]# cd zx/
[root@docker-node1 zx]# ls
_data
[root@docker-node1 zx]# cd _data/
[root@docker-node1 _data]# ls
file

4、企业示例

利用容器编排完成haproxy和nginx负载均衡架构实施

[root@docker-node1 ~]# cd test/
[root@docker-node1 test]# mkdir -p /var/lib/docker/volumes/conf
[root@docker-node1 ~]# dnf install haproxy -y --downloadonly --downloaddir=/mnt
[root@docker-node1 ~]# cd /mnt
[root@docker-node1 mnt]# rpm2cpio haproxy-2.4.17-6.el9.x86_64.rpm | cpio -id
13421 blocks
[root@docker-node1 mnt]# cd /etc
[root@docker-node1 etc]# ls
haproxy  logrotate.d  sysconfig
[root@docker-node1 etc]# cd haproxy/
[root@docker-node1 haproxy]# ls
conf.d  haproxy.cfg
[root@docker-node1 haproxy]# cp haproxy.cfg /var/lib/docker/volumes/conf/
[root@docker-node1 haproxy]# cd /var/lib/docker/volumes/conf/
[root@docker-node1 conf]# ls
haproxy.cfg

[root@docker-node1 conf]# vim haproxy.cfg 
添加以下四行:
listen webcluster
  bind *:80
  balance roundrobin
  server web1 webserver1:80 check inter 3 fall 3 rise 5
  server web2 webserver2:80 check inter 3 fall 3 rise 5

[root@docker-node1 ~]# docker load -i haproxy-2.3.tar.gz 
[root@docker-node1 ~]# cd test/
[root@docker-node1 test]# vim haproxy.yml
[root@docker-node1 test]# docker compose -f haproxy.yml config
[root@docker-node1 test]# cat haproxy.yml
services:
  web1:
    image: nginx:latest
    container_name: webserver1
    restart: always
    networks:
      - mynet1
    expose:
      - 80
    volumes:
      - data_web1:/usr/share/nginx/html
  web2:
    image: nginx:latest
    container_name: webserver2
    restart: always
    networks:
      - mynet1
    expose:
      - 80
    volumes:
      - data_web2:/usr/share/nginx/html

  haproxy:
    image: haproxy:2.3
    container_name: haproxy
    restart: always
    networks:
      - mynet1
      - mynet2
    volumes:
      - /var/lib/docker/volumes/conf/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
    ports:
      - 80:80

networks:
  mynet1:
    driver: bridge
  mynet2:
    driver: bridge

volumes:
  data_web1:
    name: data_web1
  data_web2:
    name: data_web2

[root@docker-node1 test]# docker compose -f haproxy.yml up -d
[+] Running 7/7
 ✔ Network test_mynet2   Created                                                   0.3s 
 ✔ Network test_mynet1   Created                                                   0.4s 
 ✔ Volume "data_web1"    Created                                                   0.0s 
 ✔ Volume "data_web2"    Created                                                   0.0s 
 ✔ Container webserver2  Started                                                   1.8s 
 ✔ Container haproxy     Started                                                   2.2s 
 ✔ Container webserver1  Started                                                   2.0s 

[root@docker-node1 test]# netstat -antlupe | grep 80
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      0          117692     22682/docker-proxy  
tcp6       0      0 :::80                   :::*                    LISTEN      0          118183     22704/docker-proxy  
[root@docker-node1 test]# 
[root@docker-node1 test]# docker compose ps
NAME         IMAGE          COMMAND                  SERVICE   CREATED          STATUS          PORTS
haproxy      haproxy:2.3    "docker-entrypoint.s…"   haproxy   47 seconds ago   Up 46 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp
webserver1   nginx:latest   "/docker-entrypoint.…"   web1      47 seconds ago   Up 47 seconds   80/tcp
webserver2   nginx:latest   "/docker-entrypoint.…"   web2      47 seconds ago   Up 46 seconds   80/tcp

[root@docker-node1 test]# echo webserver1 > /var/lib/docker/volumes/data_web1/_data/index.html 
[root@docker-node1 test]# echo webserver2 > /var/lib/docker/volumes/data_web2/_data/index.html 

;