当前位置: 首页 > news >正文

快速了解Docker容器技术

目录

一 、Docker简介及部署方法

1.1 Docker简介

 1.1.1 什么是docker?

1.1.2 docker在企业中的应用场景

1.1.3 docker与虚拟化的对比

1.1.4 docker的优势

二 、部署docker

2.1 容器工作方法

2.2 部署第一个容器

2.2.1 配置软件仓库

2.2.2 安装docker-ce并启动服务

2.2.3 激活内核网络选项

二 Docker的基本操作

2.1 Docker镜像管理

2.1.1 搜索镜像

2.1.2 拉取镜像

2.1.3 查看镜像信息

2.1.4 导出镜像

2.1.5 删除镜像

2.2 容器的常用操作

2.2.1 启动容器

2.2.2 查看容器运行信息

2.2.3 停止和运行容器

2.2.4 删除容器

2.2.5 容器内容提交

2.2.6 系统中的文件和容器中的文件传输

2.2.7 查询容器内部日志

三、docker镜像构建

3.1 docker镜像结构

3.2 镜像运行的基本原理

3.3 镜像获得方式

3.4 镜像构建

3.4.1 构建参数

3.4.2 Dockerfile实例

3.4.2.1 建立构建目录,编写构建文件

3.4.2.2 通过dockerfile生成镜像

3.4.2.3 测试镜像可用性

3.4.2.4 查看容器详情

3.5 镜像优化方案

3.5.1 镜像优化策略

3.5.2 镜像优化示例

四、docker 镜像仓库的管理

4.1 什么是docker仓库

4.2 docker hub

4.2.1 docker hub的使用方法

4.3 docker仓库的工作原理

4.3.1 pull原理

4.3.2 push原理

4.3 搭建docker的私有仓库

4.3.1 为什么搭建私有仓库

4.3.2 搭建简单的Registry仓库

4.3.3 为Registry提加密传输

4.3.4 为仓库建立登陆认证

4.4 构建企业级私有仓库

4.4.1 部署harbor

注意:要打开windows中C:\Windows\System32\drivers\etc\hosts,输入你的IP地址和你在认证中填写的DNS中的名称

4.4.2 管理仓库

五 Docker 网络

5.1 docker原生bridge网路

5.2 docker原生网络host

5.3 docker 原生网络none

5.4 docker的自定义网络

5.4.1 自定义桥接网络

5.4.2 为什么要自定义桥接

5.4.3 如何让不同的自定义网络互通?

5.4.4 joined容器网络

5.4.5 joined网络示例演示

5.5. 容器内外网的访问

5.5.1 容器访问外网

5.5.2 外网访问docker容器

5.6 docker跨主机网络

5.6.1 CNM (Container Network Model)

5.6.2 macvlan网络方式实现跨主机通信

六 Docker 数据卷管理及优化

6.1 为什么要用数据卷

6.2 bind mount 数据卷

6.3 docker managed 数据卷

6.4 数据卷容器(Data Volume Container)

6.5 bind mount 数据卷和docker managed 数据卷的对比

6.6 备份与迁移数据卷

七 Docker 的安全优化

7.1 Docker的资源限制

7.1.1.限制cpu使用

7.1.2 限制内存使用

7.1.3 限制docker的磁盘io

7.2 Docker的安全加固

7.2.1 Docker默认隔离性

7.2.2 解决Docker的默认隔离性

7.2.3 容器特权

7.2.4 容器特权的白名单

八 容器编排工具Docker Compose

8.1 Docker Compose 概述

8.2 Docker Compose 的常用命令参数

8.3 服务状态查看

8.4 构建和重新构建服务(了解)

8.5 其他操作

8.6 Docker Compose 的yml文件

8.6.1 服务(services)

8.6.2 网络(networks)

8.6.3 存储卷(volumes)

8.7 企业示例


 、Docker简介及部署方法

1.1 Docker简介

Docker 之父 Solomon Hykes Docker 就好比传统的货运集装箱
注意:
2008 年LXC(LinuX Contiainer)发布,但是没有行业标准,兼容性非常差
docker2013年首次发布,由Docker, Inc开发

 1.1.1 什么是docker

Docker 是管理容器的引擎,为应用打包、部署平台,而非单纯的虚拟化技术
它具有以下几个重要特点和优势:
1. 轻量级虚拟化
  • Docker 容器相较于传统的虚拟机更加轻量和高效,能够快速启动和停止,节省系统资源。
  • 例如,启动一个 Docker 容器可能只需要几秒钟,而启动一个虚拟机则可能需要几分钟。
2. 一致性 . 致性
  • 确保应用程序在不同的环境中(如开发、测试、生产)具有一致的运行表现。
  • 无论在本地还是云端,应用的运行环境都能保持相同,减少了因环境差异导致的问题。
3. 可移植性
  • 可以轻松地将 Docker 容器从一个平台迁移到另一个平台,无需担心依赖和环境配置的差异。
  • 比如,在本地开发的容器可以无缝部署到云服务器上。
4. 高效的资源利用
  • 多个 Docker 容器可以共享主机的操作系统内核,从而更有效地利用系统资源。
5. 易于部署和扩展
  • 能够快速部署新的应用实例,并且可以根据需求轻松地进行水平扩展。
  • 总之,Docker 极大地简化了应用程序的开发、部署和管理流程,提高了开发效率和运维的便利性。
  • 它在现代软件开发和云计算领域得到了广泛的应用。

1.1.2 docker在企业中的应用场景

  • 在企业中docker作为业务的最小载体而被广泛应用
  • 通过docker企业可以更效率的部署应用并更节省资源

注意:

IaaS(Infrastructure as a Service),即基础设施即服务
PaaS是(Platform as a Service)即指平台即服务
SaaS(Software as a Service)软件运营服务是

1.1.3 docker与虚拟化的对比

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

1.1.4 docker的优势

  • 对于开发人员:Build onceRun anywhere
  • 对于运维人员:Configure onceRun anything
  • 容器技术大大提升了IT人员的幸福指数!

二 、部署docker

2.1 容器工作方法

2.2 部署第一个容器

官方站点: https://docs.docker.com/

2.2.1 配置软件仓库

[root@docker ~]# cd /etc/yum.repos.d/

[root@docker yum.repos.d]# vim docker.repo         #这是在RHEL9中做的配置
[doocker]
name=docker
baseurl=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/rhel/9/x86_64/stable/
enabled=1
gpgcheck=0

[root@docker yum.repos.d]# yum makecache 


[root@docker ~]# cd /etc/yum.repos.d/

[root@docker yum.repos.d]# vim docker.repo         #这是在RHEL7中做的配置

[docker]
name=docker-ce
baseurl=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/7/x86_64/stable/
gpgcheck=0
[centos]
name=extras
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos/7/extras/x86_64
gpgcheck=0
[root@docker yum.repos.d]# yum makecache 

2.2.2 安装docker-ce并启动服务

#安装docker

[root@docker ~]# yum install -y docker-ce.x86_64
#如果出现下面错误

 Problem: package docker-ce-3:27.2.0-1.el9.x86_64 requires containerd.io >= 1.6.24, but none of the providers can be installed

 package buildah-1:1.27.0-2.el9.x86_64 requires runc >= 1.0.0-26, but none of the providers can be installed

#需要卸载containerd.io和 runc,然后再进行安装

[root@docker ~]# yum remove containerd.io runc

[root@docker ~]# yum install -y docker-ce.x86_64

#编辑docker启动文件,设定其使用iptables的网络设定方式,默认使用nftables
[root@docker ~]# vim /usr/lib/systemd/system/docker.service 
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
--iptables=true
[root@docker ~]# systemctl enable --now docker.service 
Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /usr/lib/systemd/system/docker.service.
[root@docker ~]# docker info

2.2.3 激活内核网络选项

# rhel7 中 需要
[root@docker ~]# vim /etc/sysctl.d/docker.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
[root@docker ~]# sysctl --system
[root@docker ~]# systemctl restart docker

Docker的基本操作

2.1 Docker镜像管理

2.1.1 搜索镜像

[root@docker ~]# docker search nginx

NAME                              DESCRIPTION                                     STARS     OFFICIAL
nginx                             Official build of Nginx.                        20126     [OK]

nginx/nginx-quic-qns              NGINX QUIC interop                              1         
nginx/nginx-prometheus-exporter   NGINX Prometheus Exporter for NGINX and NGIN…   43        
nginx/nginx-ingress               NGINX and  NGINX Plus Ingress Controllers fo…   94        
nginx/nginx-ingress-operator      NGINX Ingress Operator for NGINX and NGINX P…   2         
nginx/unit                        This repository is retired, use the Docker o…   63        
nginx/unit-preview                Unit preview features                           0         
bitnami/nginx                     Bitnami container image for NGINX               193       
rapidfort/nginx                   RapidFort optimized, hardened image for NGINX   15        
kasmweb/nginx                     An Nginx image based off nginx:alpine and in…   8         
ubuntu/nginx                      Nginx, a high-performance reverse proxy & we…   116       
chainguard/nginx                  Minimal Wolfi-based nginx HTTP, reverse prox…   2         
jitesoft/nginx                    Nginx on alpine linux                           0         
dockette/nginx                    Nginx SSL / HSTS / HTTP2                        3         
geokrety/nginx                    Our customized nginx image                      0         
gluufederation/nginx               A customized NGINX image containing a consu…   1         
docksal/nginx                     Nginx service image for Docksal                 0         
circleci/nginx                    This image is for internal use                  2         
okteto/nginx                                                                      0         
objectscale/nginx                                                                 0         
intel/nginx                                                                       0         
bitnamicharts/nginx                                                               0         
vmware/nginx                                                                      2         
rancher/nginx                                                                     2         
linuxserver/nginx                 An Nginx container, brought to you by LinuxS…   217  


参数说明
NAME
镜像名称
DESCRIPTION
镜像说明
STARS
点赞数量
OFFICIAL
是否是官方的

2.1.2 拉取镜像

#首先需要一个镜像加速器
[root@docker ~]# cd /etc/docker/
[root@docker docker]# ls
[root@docker docker]# vim daemon.json
{
  "registry-mirrors": ["https://1d9tqcvx.mirror.aliyuncs.com"]
}
[root@docker docker]# systemctl daemon-reload 
[root@docker docker]# systemctl restart docker
[root@docker docker]# 
#从镜像仓库中拉取镜像
[root@docker docker]# docker pull busybox
[root@docker ~]# docker pull nginx:1.26-alpine
#如果实在拉取不下来就找到所需的.gz包,在导入docker中
[root@docker packages]# docker load -i game2048.tar.gz 
011b303988d2: Loading layer   5.05MB/5.05MB
36e9226e74f8: Loading layer  51.46MB/51.46MB
192e9fad2abc: Loading layer  3.584kB/3.584kB
6d7504772167: Loading layer  4.608kB/4.608kB
88fca8ae768a: Loading layer  629.8kB/629.8kB
Loaded image: timinglee/game2048:latest
[root@docker packages]# docker load -i mario.tar.gz 
4aeeaca5ce76: Loading layer  197.2MB/197.2MB
708fd576a927: Loading layer  208.9kB/208.9kB
90222f49bc4c: Loading layer  4.608kB/4.608kB
5f70bf18a086: Loading layer  1.024kB/1.024kB
dbe97b1b7330: Loading layer  1.536kB/1.536kB
44e5704d49fb: Loading layer  9.912MB/9.912MB
Loaded image: timinglee/mario:latest
[root@docker packages]# docker load -i nginx-latest.tar.gz 
9853575bc4f9: Loading layer  77.83MB/77.83MB
72db5db515fd: Loading layer    114MB/114MB
8b87c0c66524: Loading layer  3.584kB/3.584kB
ec1a2ca4ac87: Loading layer  4.608kB/4.608kB
55e54df86207: Loading layer   2.56kB/2.56kB
f4f00eaedec7: Loading layer   5.12kB/5.12kB
5f0272c6e96d: Loading layer  7.168kB/7.168kB
Loaded image: nginx:latest
[root@docker packages]# docker load -i busybox-latest.tar.gz 
d51af96cf93e: Loading layer  4.495MB/4.495MB
Loaded image: busybox:latest
#查看本地镜像
[root@docker ~]# docker images
REPOSITORY           TAG       IMAGE ID       CREATED         SIZE
nginx                latest    5ef79149e0ec   2 weeks ago     188MB
busybox              latest    65ad0d468eb1   15 months ago   4.26MB
timinglee/game2048   latest    19299002fdbe   7 years ago     55.5MB
timinglee/mario      latest    9a35a9e43e8c   9 years ago     198MB
[root@docker ~]# docker run -d --rm --name game1 -p 80:80 timinglee/game2048:latest 
3846e030568259d638be802ca4e0324b9081e86d33f1c964576361b739eaf10b
[root@docker ~]# docker ps
CONTAINER ID   IMAGE                       COMMAND                  CREATED          STATUS          PORTS                                        NAMES
3846e0305682   timinglee/game2048:latest   "/bin/sh -c 'sed -i …"   44 seconds ago   Up 43 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp, 443/tcp   game1
#强制删除镜像
[root@docker ~]# docker rm -f game1 
game1

[root@docker ~]# docker run -d --rm --name game2 -p 80:8080 timinglee/mario:latest 
c663333278415773f1e566c85c40dee6f270011f92df1474cd8884f31cac646c
[root@docker ~]# docker ps
CONTAINER ID   IMAGE                    COMMAND                  CREATED         STATUS         PORTS                                     NAMES
c66333327841   timinglee/mario:latest   "python3 -m http.ser…"   6 seconds ago   Up 6 seconds   0.0.0.0:80->8080/tcp, [::]:80->8080/tcp   game2

 
#强制删除镜像
[root@docker ~]# docker rm -f game2 
game2
#不清楚镜像端口
[root@docker ~]# docker history timinglee/mario:latest 
IMAGE          CREATED       CREATED BY                                      SIZE      COMMENT
9a35a9e43e8c   9 years ago   /bin/sh -c #(nop) CMD ["python3" "-m" "http.…   0B        
<missing>      9 years ago   /bin/sh -c #(nop) EXPOSE
8080/tcp               0B        
<missing>      9 years ago   /bin/sh -c #(nop) WORKDIR /app                  0B        
<missing>      9 years ago   /bin/sh -c #(nop) COPY dir:02930d36f63824e72…   9.81MB    
<missing>      9 years ago   /bin/sh -c apt-get install -y python3           0B        
<missing>      9 years ago   /bin/sh -c #(nop) MAINTAINER Pavel 'PK' Kami…   0B        
<missing>      9 years ago   /bin/sh -c #(nop) CMD ["/bin/bash"]             0B        
<missing>      9 years ago   /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$…   1.9kB     
<missing>      9 years ago   /bin/sh -c echo '#!/bin/sh' > /usr/sbin/poli…   195kB     
<missing>      9 years ago   /bin/sh -c #(nop) ADD file:5a3f9e9ab88e725d6…   188MB     

注意:alpine 版本:nginx镜像的最小安装发型版本

1) 运行game2048:latest 效果图:

2)运行mario:latest 效果图:

2.1.3 查看镜像信息

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

2.1.4 导出镜像

#保存镜像
[root@docker ~]# docker image save nginx:latest -o nginx-latest.tar.gz
[root@docker ~]# docker image save busybox:latest -o busybox-latest.tar.gz
[root@docker ~]# ls

nginx-latest.tar.gz        busybox-latest.tar.gz
#保存所有镜像
[root@docker ~]# docker images | awk 'NR>1{print $1":"$2}'
nginx:latest
busybox:latest
timinglee/game2048:latest
timinglee/mario:latest
NR>1NRawk内置的一个变量,代表当前处理的是第几行记录。 NR>1意味着只处理第2行及之后的行(即跳过第一行,通常是标题行)
[root@docker ~]# docker save `docker images | awk 'NR>1{print $1":"$2}'` -o images.tar.gz
[root@docker ~]# ls
images.tar.gz

注意:

  • -o:指定导出镜像的位置;
  • 可以同时导出多个镜像到一个文件中;
  • 指定.tar.gz 可以导出并压缩。

2.1.5 删除镜像

[root@docker ~]# docker rmi nginx:latest 
Untagged: nginx:latest
Deleted: sha256:5ef79149e0ec84a7a9f9284c3f91aa3c20608f8391f5445eabe92ef07dbda03c
Deleted: sha256:aa557aaf0b93b5b9af247beb198be89632444af2d52b37f2b67bdf2227194625
Deleted: sha256:85dee7d6fa4b70eaa6b43b5dede5255b6794fac35d2aa6a80f8590dad223c1a6
Deleted: sha256:9996f8429bfc2f1e10f561e17bdc0c66eb82e30088725fbdc634a774933ba066
Deleted: sha256:d861b1c34411369feaaaf4921018baa607e89f1c393b8ed950f676dd3349b9ff
Deleted: sha256:01b9716819d1d6863f886e1adcd8bb2bf936dcacb16e1750e873bfd8e1667014
Deleted: sha256:8d8c7099ecd8343e6700c1d348211ab159c0eda2a9d318c5cf600a8eb2588f5e
Deleted: sha256:9853575bc4f955c5892dd64187538a6cd02dba6968eba9201854876a7a257034

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

2.2 容器的常用操作

2.2.1 启动容器

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

[root@docker ~]# docker run -it --name centos7 centos:7 
[root@0eaf80e611a5 /]# #进入到容器中,按<ctrl>+<d>退出并停止容器,#按<ctrl>+<pq>退出但不停止容器

#重新进入容器
#如果使用 <ctrl>+<d> 则需要docker start centos7 ,如果使用 <ctrl>+<pq> 则直接docker attach centos7 。关闭容器是docker stop centos7 
[root@docker ~]# docker attach centos7 
[root@0eaf80e611a5 /]#
#在容器中执行命令

[root@docker ~]# docker exec -it game1 ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:ac:11:00:02  
          inet addr:172.17.0.2  Bcast:172.17.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:2294 (2.2 KB)  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)


-d                         #后台运行
-i                         #交互式运行
-t                         #打开一个终端
--name                 #指定容器名称
-p                         #端口映射 -p 80:8080         把容器8080端口映射到本机80端口
--rm                      #容器停止自动删除容器
--network             #指定容器使用的网络

2.2.2 查看容器运行信息

[root@docker ~]# docker run -d --rm --name busybox busybox:latest 
1eaa51c9d9055be7fba8f487fb1008417efd409cff85d7a9f274bf64750dae6e
[root@docker ~]# 


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

[root@docker ~]# docker ps -a        #查看所有容器
CONTAINER ID   IMAGE                    COMMAND                  CREATED              STATUS                     PORTS                                              NAMES
88666c32efc8   timinglee/game2048       "/bin/sh -c 'sed -i …"   About a minute ago   Up About a minute          443/tcp, 0.0.0.0:8080->80/tcp, [::]:8080->80/tcp   game
e75df8d2fbd3   timinglee/mario:latest   "python3 -m http.ser…"   2 minutes ago        Up 2 minutes               0.0.0.0:80->8080/tcp, [::]:80->8080/tcp            game1
ded858c1eaa3   busybox:latest           "sh"                     2 minutes ago        Exited (0) 2 minutes ago                                                      busybox

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

2.2.3 停止和运行容器

[root@docker ~]# docker stop busybox                #停止容器
busybox

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

[root@docker ~]# docker start busybox                 #开启停止的容器
busybox

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

2.2.4 删除容器

[root@docker ~]# docker rm busybox                 #删除停止的容器
busybox

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

[root@docker ~]# docker run -d --rm --name game1 -p 80:8080 timinglee/mario:latest 
39d25d720bf93a03242117395e36e41385366f38de0ea17b13c853957e78877e
[root@docker ~]# docker run -d --rm --name game -p 8080:80 timinglee/game2048:latest 
ea8f9d98a237a7d853120e607de21c1afc6569e2463985f318ff29ba702ddb8b
[root@docker ~]# docker ps
CONTAINER ID   IMAGE                       COMMAND                  CREATED          STATUS          PORTS                                              NAMES
ea8f9d98a237   timinglee/game2048:latest   "/bin/sh -c 'sed -i …"   8 seconds ago    Up 8 seconds    443/tcp, 0.0.0.0:8080->80/tcp, [::]:8080->80/tcp   game
39d25d720bf9   timinglee/mario:latest      "python3 -m http.ser…"   43 seconds ago   Up 42 seconds   0.0.0.0:80->8080/tcp, [::]:80->8080/tcp            game1
[root@docker ~]# docker stop game
game
[root@docker ~]# docker stop game1
game1


[root@docker ~]# docker container prune -f                #删除所有停止的容器
Total reclaimed space: 0B
[root@docker ~]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
[root@docker ~]#       

2.2.5 容器内容提交


  • 默认情况下,容器被删除后,在容器中的所有操作都会被清理,包括要保存的文件
  • 如果想永久保存,那么我们需要把动作提交,提交后会生成新的镜像
  • 当我们在运行新镜像后即可看到我们提交的内容

[root@docker ~]# docker run -it --name test busybox
/ # touch opqfile                                                        #在容器中建立文件
/ # ls
bin      etc      lib      opqfile  root     tmp      var
dev      home     lib64    proc     sys      usr
/ # exit

[root@docker ~]# docker ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED          STATUS                     PORTS     NAMES
8642f1344548   busybox   "sh"      22 seconds ago   Exited (0) 6 seconds ago             test
[root@docker ~]# docker rm test                 #删掉容器后
test
[root@docker ~]# docker ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
[root@docker ~]# docker run -it --name test busybox       #删掉容器后开启新的容器文件不存在

/ # ls
bin    etc    lib    proc   sys    usr
dev    home   lib64  root   tmp    var
/ # 

[root@docker ~]# docker commit -m "add opqfile" test busybox:v1
sha256:67d7df8d26c5e9376142abd33cc98422a74d4dec2c9f5e11ade93f13f54a0142

[root@docker ~]# docker images
REPOSITORY           TAG       IMAGE ID       CREATED          SIZE
busybox              v1        67d7df8d26c5   29 seconds ago   4.26
 

[root@docker ~]# docker image history busybox:v1 
IMAGE          CREATED              CREATED BY                          SIZE      COMMENT
67d7df8d26c5   About a minute ago   sh                                  5B        add opqfile
65ad0d468eb1   15 months ago        BusyBox 1.36.1 (glibc), Debian 12   4.26MB  

注意:此方法不利于企业审计,所以不推荐使用,在企业中我们多用Dockerfile来构建镜像

2.2.6 系统中的文件和容器中的文件传输

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

[root@docker ~]# docker cp /etc/fstab test:/fstab          #把本机文件复制到容器中
Successfully copied 2.56kB to test:/fstab

2.2.7 查询容器内部日志

[root@docker ~]# docker logs test
/ # exit
/ # 
/ # 
/ # ls
bin    etc    lib    proc   sys    usr
dev    home   lib64  root   tmp    var
/ # touch opqfile
/ # ls
bin      etc      lib      opqfile  root     tmp      var
dev      home     lib64    proc     sys      usr
/ # exit
/ # 
/ # 
/ # ls
bin      etc      lib      opqfile  root     tmp      var
dev      home     lib64    proc     sys      usr
/ # exit
/ # 
/ # 
/ # ls
bin      dev      etc      fstab    home     lib      lib64    opqfile  proc     root     sys      tmp      usr      var
/ # exit
[root@docker ~]# 

三、docker镜像构建

3.1 docker镜像结构


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

3.2 镜像运行的基本原理


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

3.3 镜像获得方式

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

3.4 镜像构建

3.4.1 构建参数

FROM
指定 base 镜像 eg FROM busybox:version
COPY
复制文件 eg COPY file /file 或者 COPY [“file”,”/”]
MAINTAINER
指定作者信息,比如邮箱 eg MAINTAINER user@example.com
在最新版的 docker 中用 LABEL KEY="VALUE" 代替
ADD
功能和 copy 相似,指定压缩文件或 url eg: ADD test.tar /mnt 或者 eg 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 功能和用法类似,但动作不可被覆盖
参数示例及用法
#FROM COPY 和MAINTAINER
[root@docker ~]# mkdir docker
[root@docker ~]# cd docker/
[root@docker docker]# touch opqfile 
[root@docker docker]# vim Dockerfile 
FROM busybox:latest                         #指定使用的基础镜像         
LABEL KEY=jin@docker.com             #指定作者信息    
COPY opqfile /                                     #复制当前目录文件到容器指定位置,leefile必须在当前目录中    
[root@docker docker]# docker build -t example:v1 .                        #构建镜像
[+] Building 0.1s (7/7) FINISHED                    docker:default
 => [internal] load build definition from Dockerfile          0.0s
 => => transferring dockerfile: 97B                           0.0s
 => [internal] load metadata for docker.io/library/busybox:l  0.0s
 => [internal] load .dockerignore                             0.0s
 => => transferring context: 2B                               0.0s
 => [internal] load build context                             0.0s
 => => transferring context: 26B                              0.0s
 => [1/2] FROM docker.io/library/busybox:latest               0.0s
 => CACHED [2/2] COPY opqfile /                               0.0s
 => exporting to image                                        0.0s
 => => exporting layers                                       0.0s
 => => writing image sha256:ca24894d5d14dd8fc7c8febebf0b1a95  0.0s
 => => naming to docker.io/library/example:v1                 0.0s
#ADD
[root@docker docker]# touch opqfile{1..10}
[root@docker docker]# tar zcf opqfile.gz opqfile*
[root@docker docker]# cat Dockerfile 
FROM busybox:latest
LABEL KEY=jin@docker.com
COPY opqfile /
ADD opqfile.gz / 
[root@docker docker]# docker build -t example:v2 .
[+] Building 0.2s (8/8) FINISHED                    docker:default
 => [internal] load build definition from Dockerfile          0.0s
 => => transferring dockerfile: 115B                          0.0s
 => [internal] load metadata for docker.io/library/busybox:l  0.0s
 => [internal] load .dockerignore                             0.0s
 => => transferring context: 2B                               0.0s
 => [1/3] FROM docker.io/library/busybox:latest               0.0s
 => [internal] load build context                             0.0s
 => => transferring context: 290B                             0.0s
 => CACHED [2/3] COPY opqfile /                               0.0s
 => [3/3] ADD opqfile.gz /                                    0.1s
 => exporting to image                                        0.0s
 => => exporting layers                                       0.0s
 => => writing image sha256:2ab6430e5ea5bc47206d68c314fa7b1f  0.0s
 => => naming to docker.io/library/example:v2                 0.0s
[root@docker docker]# docker run -it --rm --name test example:v2
/ # ls
bin        lib        opqfile10  opqfile5   opqfile9   tmp
dev        lib64      opqfile2   opqfile6   proc       usr
etc        opqfile    opqfile3   opqfile7   root       var
home       opqfile1   opqfile4   opqfile8   sys
 
#ENV CMD
[root@docker docker]# cat Dockerfile 
FROM busybox:latest
LABEL KEY=jin@docker.com
ENV NAME welcome to login 
CMD echo $NAME


 

[root@docker docker]# docker build -t example:v3 .
[+] Building 0.1s (8/8) FINISHED                    docker:default
 => [internal] load build definition from Dockerfile          0.0s
 => => transferring dockerfile: 156B                          0.0s
 => WARN: LegacyKeyValueFormat: "ENV key=value" should be us  0.0s
 => WARN: JSONArgsRecommended: JSON arguments recommended fo  0.0s
 => [internal] load metadata for docker.io/library/busybox:l  0.0s
 => [internal] load .dockerignore                             0.0s
 => => transferring context: 2B                               0.0s
 => [1/3] FROM docker.io/library/busybox:latest               0.0s
 => [internal] load build context                             0.0s
 => => transferring context: 56B                              0.0s
 => CACHED [2/3] COPY opqfile /                               0.0s
 => CACHED [3/3] ADD opqfile.gz /                             0.0s
 => exporting to image                                        0.0s
 => => exporting layers                                       0.0s
 => => writing image sha256:6de93f2ffa097037127539e7788f1386  0.0s
 => => naming to docker.io/library/example:v3                 0.0s

 2 warnings found (use docker --debug to expand):
 - LegacyKeyValueFormat: "ENV key=value" should be used instead of legacy "ENV key value" format (line 3)
 - JSONArgsRecommended: JSON arguments recommended for CMD to prevent unintended behavior related to OS signals (line 6)
[root@docker docker]# docker history example:v3
IMAGE          CREATED          CREATED BY                          SIZE      COMMENT
6de93f2ffa09   7 minutes ago    CMD ["/bin/sh" "-c" "echo $NAME"]   0B        buildkit.dockerfile.v0
<missing>      7 minutes ago    ADD opqfile.gz / # buildkit         0B        buildkit.dockerfile.v0
<missing>      33 minutes ago   COPY opqfile / # buildkit           0B        buildkit.dockerfile.v0
<missing>      33 minutes ago   ENV NAME=welcome to login           0B        buildkit.dockerfile.v0
<missing>      33 minutes ago   LABEL KEY=jin@docker.com            0B        buildkit.dockerfile.v0
<missing>      15 months ago    BusyBox 1.36.1 (glibc), Debian 12   4.26MB    
[root@docker docker]# docker run -it --rm --name test example:v3
welcome to login
[root@docker docker]# 

#后面的构建镜像不会出现任何错误
[root@docker dockevim Dockerfile 
FROM busybox:latest
LABEL KEY=jin@docker.com
ENV NAME="welcome to login"
#CMD echo $NAME
CMD ["/bin/echo", "$NAME"]
#CMD ["/bin/sh", "-c",  "/bin/echo $NAME"]
[root@docker docker]# docker rmi example:v3
Untagged: example:v3
Deleted: sha256:9799d658663abe2d5c7f4ba367ee8a248089cda2afb2e26de988afe0fc7ea915
[root@docker docker]# docker build -t example:v3 .
[root@docker docker]# docker run -it --rm --name test example:v3
$NAME
[root@docker docker]#
#ENV CMD
[root@docker docke]# vim Dockerfile 
FROM busybox:latest
LABEL KEY=jin@docker.com
ENV NAME="welcome to login"
#CMD echo $NAME
#CMD ["/bin/echo", "$NAME"]
CMD ["/bin/sh", "-c",  "/bin/echo $NAME"]
[root@docker docker]# docker rmi example:v3
Untagged: example:v3
Deleted: sha256:9799d658663abe2d5c7f4ba367ee8a248089cda2afb2e26de988afe0fc7ea915
[root@docker docker]# docker build -t example:v3 .
[root@docker docker]# docker run -it --rm --name test example:v3
welcome to login
[root@docker docker]#
#ENTRYPOINT
[root@docker docker]# vim Dockerfile 
FROM busybox:latest
LABEL KEY=jin@docker.com
ENV NAME="welcome to login"

#ENTRYPOINT echo $NAME
#ENTRYPOINT ["/bin/echo", "$NAME"]
ENTRYPOINT ["/bin/sh", "-c", "/bin/echo $NAME"]
#第一个会报警告,但是可以执行
[root@docker docker]# docker build -t example:v4 .
1 warning found (use docker --debug to expand):
 - JSONArgsRecommended: JSON arguments recommended for ENTRYPOINT to prevent unintended behavior related to OS signals (line 9)
[root@docker docker]# docker run -it --rm --name test example:v4 sh
welcome to login
#第二、三个不会报错
[root@docker docker]# docker rmi example:v4
[root@docker docker]# docker build -t example:v4 .
[root@docker docker]# docker run -it --rm --name test example:v4 sh
$NAME sh

[root@docker docker]# docker rmi example:v4
[root@docker docker]# docker build -t example:v4 .
[root@docker docker]# docker run -it --rm --name test example:v4 sh
welcome to login
 
#EXPOSE VOLUME VOLUME
[root@docker docker]# docker run -it --rm --name test example:v5
/var/www/html # ls
opqfile
/var/www/html # ll
sh: ll: not found
/var/www/html # exit
[root@docker docker]# cat Dockerfile 
FROM busybox:latest
LABEL KEY=jin@docker.com
ENV NAME="welcome to login"
EXPOSE 80 443
VOLUME /var/www/html
WORKDIR /var/www/html
RUN touch opqfile
[root@docker docker]# docker build -t example:v5 .
[+] Building 0.4s (7/7) FINISHED                    docker:default
 => [internal] load build definition from Dockerfile          0.0s
 => => transferring dockerfile: 416B                          0.0s
 => [internal] load metadata for docker.io/library/busybox:l  0.0s
 => [internal] load .dockerignore                             0.0s
 => => transferring context: 2B                               0.0s
 => CACHED [1/3] FROM docker.io/library/busybox:latest        0.0s
 => [2/3] WORKDIR /var/www/html                               0.0s
 => [3/3] RUN touch opqfile                                   0.2s
 => exporting to image                                        0.1s
 => => exporting layers                                       0.1s
 => => writing image sha256:218b9d93daf5fc167e243b7e1cc606b7  0.0s
 => => naming to docker.io/library/example:v5                 0.0s
[root@docker docker]# docker history example:v5
IMAGE          CREATED              CREATED BY                                SIZE      COMMENT
218b9d93daf5   About a minute ago   RUN /bin/sh -c touch opqfile # buildkit   0B        buildkit.dockerfile.v0
<missing>      About a minute ago   WORKDIR /var/www/html                     0B        buildkit.dockerfile.v0
<missing>      About a minute ago   VOLUME [/var/www/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   ENV NAME=welcome to login                 0B        buildkit.dockerfile.v0
<missing>      About a minute ago   LABEL KEY=jin@docker.com                  0B        buildkit.dockerfile.v0
<missing>      15 months ago        BusyBox 1.36.1 (glibc), Debian 12         4.26MB

[root@docker docker]# docker run -it --rm --name test example:v5
/var/www/html # ls
opqfile

3.4.2 Dockerfile实例

3.4.2.1 建立构建目录,编写构建文件

[root@docker ~]# mkdir docker

[root@docker ~]# cd docker/
[root@docker docker]# cp ~/packages/nginx-1.26.1.tar.gz .
[root@docker docker]# cat Dockerfile
FROM centos-repo
ADD nginx-1.26.1.tar.gz /mnt
WORKDIR /mnt/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;"]

3.4.2.2 通过dockerfile生成镜像

[root@docker docker]# docker build -t nginx:v1 .

#如果在下载RUN yum install -y gcc make pcre-devel openssl-devel出现错误的解决办法

--------------------
   2 |     ADD nginx-1.23.tar.gz /mnt
   3 |     WORKDIR /mnt/nginx-1.23
   4 | >>> RUN yum install -y gcc make pcre-devel openssl-devel
   5 |     RUN sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc
   6 |     RUN ./configure --with-http_ssl_module --with-http_stub_status_module
--------------------
ERROR: failed to solve: process "/bin/sh -c yum install -y gcc make pcre-devel openssl-devel" did not complete successfully: exit code: 1

 

1.首先需要一个可以存储共享资源的服务

[root@docker docker]# yum install httpd
2.改变端口

[root@docker docker]# vim /etc/httpd/conf/httpd.conf 

3.重启服务

[root@docker docker]# systemctl restart httpd
4.创建挂载点目录

[root@docker docker]# mkdir /var/www/html/rhel7.9
5.如果是7的系统直接挂载,如果是9的系统需要在虚拟机上的设置——>添加——>找到并点击CD/DVD 驱动器 ——>然后点击完成——>在点击你新加的CD/DVD 驱动器——>使用TSO映射文件——>在你的本地中找到你所存放的7的iso镜像——>最后点击确定

6.进行挂载

[root@docker docker]# mount /dev/sr1 /var/www/html/rhel7.9/        #如果是7系统就sr0挂载即可,如果是9系统肯定有一个sr0,sr1,选sr1即可

7.在浏览器上看是否有镜像资源

8.进入容器

[root@docker docker]# docker run -it --name centos centos:7
 [root@docker packages]# ifconfig 
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        inet6 fe80::42:d7ff:fedf:57e9  prefixlen 64  scopeid 0x20<link>
        ether 02:42:d7:df:57:e9  txqueuelen 0  (Ethernet)
        RX packets 822  bytes 4441599 (4.2 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 936  bytes 123175 (120.2 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[root@c27cc54f6718 yum.repos.d]# rm -rf *
[root@c27cc54f6718 yum.repos.d]# ls
[root@c27cc54f6718 yum.repos.d]# vi centos7.repo
[root@c27cc54f6718 yum.repos.d]# cat centos7.repo 
[centos7]
name=centos7
baseurl=http://172.17.0.1:8888/rhel7.9
gpgcheck=0

[root@docker ~]# docker commit -m "add repo" centos centos-repo
sha256:cad3a8fcb8a2ae3a9560eb8df5474b4d96c3a4ea138af7225b9609826101b4b8

[root@docker ~]# docker images
REPOSITORY           TAG       IMAGE ID       CREATED          SIZE
centos-repo          latest    cad3a8fcb8a2   15 seconds ago   204MB


[root@c27cc54f6718 yum.repos.d]# exit
exit
[root@docker docker]# docker rm centos 
centos

3.4.2.3 测试镜像可用性

[root@docker docker]# docker images
REPOSITORY           TAG       IMAGE ID       CREATED             SIZE
nginx                v1        c67e5c1fdb8f   15 seconds ago      356MB

[root@docker docker]# docker history nginx:v1 
IMAGE          CREATED          CREATED BY                                      SIZE      COMMENT
c67e5c1fdb8f   9 minutes ago    CMD ["/usr/local/nginx/sbin/nginx" "-g" "dae…   0B        buildkit.dockerfile.v0
<missing>      9 minutes ago    VOLUME [/usr/local/nginx/html]                  0B        buildkit.dockerfile.v0
<missing>      9 minutes ago    EXPOSE map[443/tcp:{} 80/tcp:{}]                0B        buildkit.dockerfile.v0
<missing>      9 minutes ago    RUN /bin/sh -c make install # buildkit          6.11MB    buildkit.dockerfile.v0
<missing>      9 minutes ago    RUN /bin/sh -c make # buildkit                  20.6MB    buildkit.dockerfile.v0
<missing>      9 minutes ago    RUN /bin/sh -c ./configure --prefix=/usr/loc…   78.9kB    buildkit.dockerfile.v0
<missing>      11 minutes ago   RUN /bin/sh -c yum install -y gcc make pcre-…   118MB     buildkit.dockerfile.v0
<missing>      11 minutes ago   WORKDIR /mnt/nginx-1.26.1                       0B        buildkit.dockerfile.v0
<missing>      11 minutes ago   ADD nginx-1.26.1.tar.gz /mnt # buildkit         7.35MB    buildkit.dockerfile.v0
<missing>      30 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  

[root@docker docker]# docker run -d --name test nginx:v1 
8586ca7d433423c9df3daefe4c8795909a5a97cdffc8448cde82fac1dba5623b

3.4.2.4 查看容器详情

[root@docker docker]# docker inspect test

3.5 镜像优化方案

3.5.1 镜像优化策略

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

3.5.2 镜像优化示例

方法 1. 缩减镜像层
[root@docker ~]# cd docker/
[root@docker docker]# vim Dockerfile
FROM centos-repo as build
ADD nginx-1.26.1.tar.gz /mnt
WORKDIR /mnt/nginx-1.26.1
RUN yum install -y gcc make pcre-devel openssl-devel && ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_stub_status_module && make && make install && rm -rf /mnt/nginx-1.26.1 && yum clean all
EXPOSE 80 443
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]

[root@docker docker]# docker build -t nginx:v2 .
[root@docker docker]# docker images                                
REPOSITORY           TAG       IMAGE ID       CREATED          SIZE
nginx                v2        0857606154ff   36 seconds ago   292MB
nginx                v1        c67e5c1fdb8f   14 hours ago     356MB
方法 2. 多阶段构建

[root@docker docker]# vim Dockerfile
FROM centos-repo as build 
ADD nginx-1.26.1.tar.gz /mnt
WORKDIR /mnt/nginx-1.26.1
RUN yum install -y gcc make pcre-devel openssl-devel && ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_stub_status_module && make && make install && rm -rf /mnt/nginx-1.26.1 && yum clean all 

FROM centos-repo

COPY --from=build /usr/local/nginx /usr/local/nginx
EXPOSE 80 
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]

nginx                v3        fa05ebe285d6   About a minute ago   210MB
nginx                v2        0857606154ff   7 minutes ago        292MB
nginx                v1        c67e5c1fdb8f   14 hours ago         356MB

方法 3. 使用最精简镜像
使用 google 提供的最精简镜像
下载地址:
https://github.com/GoogleContainerTools/distroless
下载镜像:
docker pull gcr.io/distroless/base

[root@docker ~]# cd packages/
[root@docker packages]# docker load -i nginx-1.23.tar.gz 
8cbe4b54fa88: Loading layer [==================================================>]  84.01MB/84.01MB
5dd6bfd241b4: Loading layer [==================================================>]  62.51MB/62.51MB
043198f57be0: Loading layer [==================================================>]  3.584kB/3.584kB
2731b5cfb616: Loading layer [==================================================>]  4.608kB/4.608kB
6791458b3942: Loading layer [==================================================>]  3.584kB/3.584kB
4d33db9fdf22: Loading layer [==================================================>]  7.168kB/7.168kB
Loaded image: nginx:1.23
[root@docker packages]# docker load -i debian11.tar.gz 
5342a2647e87: Loading layer [==================================================>]  327.7kB/327.7kB
577c8ee06f39: Loading layer [==================================================>]   51.2kB/51.2kB
9ed498e122b2: Loading layer [==================================================>]  3.379MB/3.379MB
4d049f83d9cf: Loading layer [==================================================>]  1.536kB/1.536kB
af5aa97ebe6c: Loading layer [==================================================>]   2.56kB/2.56kB
ac805962e479: Loading layer [==================================================>]   2.56kB/2.56kB
bbb6cacb8c82: Loading layer [==================================================>]   2.56kB/2.56kB
2a92d6ac9e4f: Loading layer [==================================================>]  1.536kB/1.536kB
1a73b54f556b: Loading layer [==================================================>]  10.24kB/10.24kB
c048279a7d9f: Loading layer [==================================================>]  3.072kB/3.072kB
2388d21e8e2b: Loading layer [==================================================>]  225.3kB/225.3kB
8451c71f8c1e: Loading layer [==================================================>]  12.92MB/12.92MB
24aacbf97031: Loading layer [==================================================>]  3.983MB/3.983MB
6835249f577a: Loading layer [==================================================>]  1.505MB/1.505MB
Loaded image: gcr.io/distroless/base-debian11:latest
[root@docker packages]# cd
[root@docker ~]# cd docker/
[root@docker docker]# docker images
REPOSITORY                        TAG       IMAGE ID       CREATED          SIZE
nginx                             v3        fa05ebe285d6   7 minutes ago    210MB
nginx                             v2        0857606154ff   13 minutes ago   292MB
centos-repo                       latest    8d3e3b0b74d6   27 minutes ago   204MB
nginx                             v1        c67e5c1fdb8f   14 hours ago     356MB
example                           v5        218b9d93daf5   15 hours ago     4.26MB
example                           v4        af9dc79e1e91   16 hours ago     4.26MB
example                           v3        3e60bf2dde28   16 hours ago     4.26MB
example                           v2        2ab6430e5ea5   16 hours ago     4.26MB
example                           v1        ca24894d5d14   17 hours ago     4.26MB
busybox                           v1        67d7df8d26c5   17 hours ago     4.26MB
nginx                             latest    5ef79149e0ec   2 weeks ago      188MB
nginx                             1.23      a7be6198544f   15 months ago    142MB
busybox                           latest    65ad0d468eb1   15 months ago    4.26MB
centos                            7         eeb6ee3f44bd   2 years ago      204MB
timinglee/game2048                latest    19299002fdbe   7 years ago      55.5MB
timinglee/mario                   latest    9a35a9e43e8c   9 years ago      198MB
gcr.io/distroless/base-debian11   latest    2a6de77407bf   N/A              20.6MB

利用最精简镜像构建

[root@docker ~]# mkdir new
[root@docker ~]# cd new/
[root@docker new]# vim Dockerfile
[root@docker new]# cat Dockerfile
FROM nginx:latest as base

# https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
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 new]# docker build -t nginx:v4 .

[root@docker new]# docker images
nginx                             v4        e1dbc0208f54   29 seconds ago   42.1MB
nginx                             v3        fa05ebe285d6   14 minutes ago   210MB
nginx                             v2        0857606154ff   21 minutes ago   292MB

nginx                v1        c67e5c1fdb8f   14 hours ago         356MB

四、docker 镜像仓库的管理

4.1 什么是docker仓库

Docker 仓库( Docker Registry 是用于存储和分发 Docker 镜像的集中式存储库。
它就像是一个大型的镜像仓库,开发者可以将自己创建的 Docker 镜像推送到仓库中,也可以从仓库中拉取所需的镜像。
Docker 仓库可以分为公共仓库和私有仓库:
  • 公共仓库,如 Docker Hub,任何人都可以访问和使用其中的镜像。许多常用的软件和应用都有在Docker Hub 上提供的镜像,方便用户直接获取和使用。
例如,您想要部署一个 Nginx 服务器,就可以从 Docker Hub 上拉取 Nginx 的镜像。
  • 私有仓库则是由组织或个人自己搭建和管理的,用于存储内部使用的、不希望公开的镜像。
比如,一家企业为其特定的业务应用创建了定制化的镜像,并将其存储在自己的私有仓库中,以保证安全性和控制访问权限。
通过 Docker 仓库,开发者能够方便地共享和复用镜像,加速应用的开发和部署过程。

4.2 docker hub

官网: https://hub.docker.com/

Docker Hub Docker 官方提供的一个公共的镜像仓库服务。
它是 Docker 生态系统中最知名和广泛使用的镜像仓库之一,拥有大量的官方和社区贡献的镜像。
以下是 Docker Hub 的一些关键特点和优势:
1. 丰富的镜像资源:涵盖了各种常见的操作系统、编程语言运行时、数据库、 Web 服务器等众多应用的镜像。
  • 例如,您可以轻松找到 UbuntuCentOS 等操作系统的镜像,以及 MySQLRedis 等数据库的镜像。
2. 官方支持:提供了由 Docker 官方维护的一些重要镜像,确保其质量和安全性。
3. 社区贡献:开发者们可以自由上传和分享他们创建的镜像,促进了知识和资源的共享。
4. 版本管理:对于每个镜像,通常都有多个版本可供选择,方便用户根据需求获取特定版本。
5. 便于搜索:用户可以通过关键词轻松搜索到所需的镜像。

4.2.1 docker hub的使用方法

#登陆官方仓库
[root@docker ~]# docker login
Log in with your Docker ID or email address to push and pull images from Docker
Hub. If you don't have a Docker ID, head over to https://hub.docker.com/ to
create one.
You can log in with your password or a Personal Access Token (PAT). Using a
limited-scope PAT grants better security and is required for organizations using
SSO. Learn more at https://docs.docker.com/go/access-tokens/
Username: timinglee
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 ~]# cd .docker/
[root@docker .docker]# ls
config.json
[root@docker .docker]# cat config.json
{
"auths": {
"https://index.docker.io/v1/": {
"auth": "dGltaW5nbGVlOjY3NTE1MTVtaW5nemxu"
}
}
[root@docker ~]# docker tag gcr.io/distroless/base-debian11:latest
timinglee/base-debian11:latest
[root@docker ~]# docker push timinglee/base-debian11:latest
The push refers to repository [docker.io/timinglee/base-debian11]
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
latest: digest:
sha256:f8179c20f1f2b1168665003412197549bd4faab5ccc1b140c666f9b8aa958042 size:
3234

4.3 docker仓库的工作原理

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

4.3.1 pull原理

镜像拉取分为以下几步:
1.docker 客户端向 index 发送镜像拉去请求并完成与 index 的认证
2.index 发送认证 token 和镜像位置给 dockerclient
3.dockerclient 携带 token 和根据 index 指引的镜像位置取连接 registry
4.Registry 会根据 client 持有的 token index 核实身份合法性
5.index 确认此 token 合法性
6.Registry 会根据 client 的请求传递镜像到客户端

4.3.2 push原理

镜像上传的步骤:
1.client index 发送上传请求并完成用户认证
2.index 会发方 token client 来证明 client 的合法性
3.client 携带 index 提供的 token 连接 Registry
4.Registry index 合适 token 的合法性
5.index 证实 token 的合法性
6.Registry 开始接收客户端上传过来的镜像

4.3 搭建docker的私有仓库

4.3.1 为什么搭建私有仓库

docker hub 虽然方便,但是还是有限制
  • 需要internet连接,速度慢
  • 所有人都可以访问
  • 由于安全原因企业不允许将镜像放到外网
好消息是 docker 公司已经将 registry 开源,我们可以快速构建企业私有仓库
地址: https://docs.docker.com/registry/deploying/

4.3.2 搭建简单的Registry仓库

1. 下载 Registry 镜像
[root@docker ~]# docker pull registry
#上面命令如果拉取不下来
[root@docker ~]# cd packages/
[root@docker packages]# docker load -i registry.tag.gz 
ce7f800efff9: Loading layer  7.644MB/7.644MB
30609d4f10dd: Loading layer  792.6kB/792.6kB
3b6a51496c9d: Loading layer  17.55MB/17.55MB
e704e9e3e9dc: Loading layer  3.584kB/3.584kB
f019f591461d: Loading layer  2.048kB/2.048kB
Loaded image: registry:latest
2. 开启 Registry
[root@docker packages]# docker run -d -p 5000:5000 --restart=always registry:latest 
523ad56a0723af0a12e3066936a7e893f15b03f97216881412c60c63aadd5ede
[root@docker packages]# docker ps
CONTAINER ID   IMAGE             COMMAND                  CREATED         STATUS         PORTS                                       NAMES
523ad56a0723   registry:latest   "/entrypoint.sh /etc…"   7 seconds ago   Up 6 seconds   0.0.0.0:5000->5000/tcp, :::5000->5000/tcp   priceless_mendel
[root@docker packages]# 
3. 上传镜像到仓库中
#给要上传的经镜像大标签
[root@docker ~]# docker tag busybox:latest 192.168.10.110:5000/busybox:latest
 
#docker在上传的过程中默认使用https,但是我们并没有建立https认证需要的认证文件所以会报错
[root@docker ~]# docker push 192.168.10.110:5000/busybox:latest 
The push refers to repository [192.168.10.110:5000/busybox]
Get "https://192.168.10.110:5000/v2/": http: server gave HTTP response to HTTPS client

 
#配置非加密端口
[root@docker ~]# vim /etc/docker/daemon.json  
{
  "registry-mirrors": ["https://1d9tqcvx.mirror.aliyuncs.com"],
  "insecure-registries" : ["http://192.168.10.110:5000"]
}
[root@docker ~]# systemctl restart docker
[root@docker ~]# 
 
#上传镜像
[root@docker ~]# docker push 192.168.10.110:5000/busybox:latest 
The push refers to repository [192.168.10.110:5000/busybox]
d51af96cf93e: Pushed 
latest: digest: sha256:28e01ab32c9dbcbaae96cf0d5b472f22e231d9e603811857b295e61197e40a9b size: 527

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

4.3.3 Registry提加密传输

#生成认证key和证书
[root@docker ~]# vim /etc/docker/daemon.json 
[root@docker ~]# cat /etc/docker/daemon.json 
[root@docker ~]# systemctl restart docker.service 
[root@docker ~]# 

[root@docker ~]# mkdir certs
[root@docker ~]# vim /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.10.110    docker.com reg.timinglee.org
[root@docker ~]# openssl req -newkey rsa:4096 \
> -nodes -sha256 -keyout certs/timinglee.org.key \
> -addext "subjectAltName = DNS:reg.timinglee.org" \         #指定备用名称
> -x509 -days 365 -out certs/timinglee.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) []:Shaanxi
Locality Name (eg, city) [Default City]:xi'an
Organization Name (eg, company) [Default Company Ltd]:timinglee
Organizational Unit Name (eg, section) []:docker
Common Name (eg, your name or your server's hostname) []:reg.timinglee.org
Email Address []:admin@timinglee.org
# 启动 registry 仓库
[root@docker ~]# docker run -d -p 443:443 --restart=always --name registry \
>  --name registry -v /opt/registry:/var/lib/registry \
> -v /root/certs:/certs \
>  -e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
> -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/timinglee.org.crt \
>  -e REGISTRY_HTTP_TLS_KEY=/certs/timinglee.org.key registry
870bbbdd32ac2e70d9fcba55a9790ad39d6a49578075e25c0730befa4d05c8b9
[root@docker ~]#

测试:

[root@docker ~]# docker tag nginx:v3 reg.timinglee.org/nginx:v3
[root@docker ~]# docker push reg.timinglee.org/nginx:v3        #docker客户端没有key和证书

The push refers to repository [reg.timinglee.org/nginx]
Get "https://reg.timinglee.org/v2/": tls: failed to verify certificate: x509: certificate relies on legacy Common Name field, use SANs instead

# 为客户端建立证书
[root@docker ~]# mkdir -p /etc/docker/certs.d/reg.timinglee.org/
[root@docker ~]# cp /root/certs/timinglee.org.crt /etc/docker/certs.d/reg.timinglee.org/ca.crt
[root@docker ~]# systemctl restart docker

[root@docker ~]# docker push reg.timinglee.org/nginx:v3
The push refers to repository [reg.timinglee.org/nginx]
e3732086b5a3: Pushed 
8cf3fe6c5806: Pushed 
174f56854903: Pushed 
v3: digest: sha256:bcfefcd3b130f9351323483d2fdd9f680e6dd88eaf0dce950dd218ac0b0332e0 size: 947
[root@docker ~]# curl -k https://reg.timinglee.org/v2/_catalog
{"repositories":["nginx"]}

4.3.4 为仓库建立登陆认证

#安装建立认证文件的工具包

[root@docker ~]# yum install httpd-tools -y


#建立认证文件

[root@docker ~]# htpasswd -Bc auth/htpasswd timinglee     #-B 强制使用最安全加密方式,默认用md5加密


New password:                 #密码是123
Re-type new password: 
Adding password for user timinglee

#添加认证到registry容器中

[root@docker ~]# docker run -d -p 443:443 --restart=always --name registry \
>  --name registry -v /opt/registry:/var/lib/registry \
>  -v /root/certs:/certs \
> -e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
>  -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/timinglee.org.crt \
> -e REGISTRY_HTTP_TLS_KEY=/certs/timinglee.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
05474d296e809e5fc8223ddc4e01e446c4df8c511e1be808d6a86efee2a0b160

[root@docker ~]# 

[root@docker ~]#  curl -k https://reg.timinglee.org/v2/_catalog -u timinglee:123
{"repositories":["nginx"]}


#登陆测试

[root@docker ~]# docker login reg.timinglee.org
Username: timinglee 
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 ~]# docker tag busybox:latest reg.timinglee.org/busybox:latest
[root@docker ~]# docker push reg.timinglee.org/busybox
Using default tag: latest
The push refers to repository [reg.timinglee.org/busybox]
d51af96cf93e: Pushed 
latest: digest: sha256:28e01ab32c9dbcbaae96cf0d5b472f22e231d9e603811857b295e61197e40a9b size: 527
#未登陆情况下上传镜像
[root@docker ~]# docker tag nginx:v1 reg.timinglee.org/nginx:v1
[root@docker ~]# docker push reg.timinglee.org/nginx:v1
The push refers to repository [reg.timinglee.org/nginx]
efe5aba04ee5: Preparing 
2fffc4a1d081: Preparing 
09bf3016e332: Preparing 
f059fb90ff11: Preparing 
5f70bf18a086: Preparing 
c9a696737621: Preparing 
28ad3235e2db: Preparing 
174f56854903: Preparing 
no basic auth credentials

#未登陆情况下也不能下载
[root@docker ~]# docker pull reg.timinglee.org/busybox
Using default tag: latest
Error response from daemon: Head "https://reg.timinglee.org/v2/busybox/manifests/latest": no basic auth credentials

4.4 构建企业级私有仓库

下载软件包地址
https://github.com/goharbor/harbor/releases
Harbor 是由 vmware 公司开源的企业级 Docker Registry 项目。
它提供了以下主要功能和特点:
1. 基于角色的访问控制( RBAC ):可以为不同的用户和用户组分配不同的权限,增强了安全性和管理的灵活性。
2. 镜像复制:支持在不同的 Harbor 实例之间复制镜像,方便在多个数据中心或环境中分发镜像。
3. 图形化用户界面( UI ):提供了直观的 Web 界面,便于管理镜像仓库、项目、用户等。
4. 审计日志:记录了对镜像仓库的各种操作,有助于追踪和审查活动。
5. 垃圾回收:可以清理不再使用的镜像,节省存储空间。

4.4.1 部署harbor

[root@docker packages]# tar zxf harbor-offline-installer-v2.5.4.tgz

[root@docker packages]# cd harbor/
[root@docker harbor]# ls
common.sh             harbor.yml.tmpl  LICENSE
harbor.v2.5.4.tar.gz  install.sh       prepare


[root@docker harbor]# cp harbor.yml.tmpl harbor.yml
[root@docker harbor]# vim harbor.yml

hostname: reg.timinglee.org
certificate: /data/certs/timinglee.org.crt
private_key: /data/certs/timinglee.org.key
harbor_admin_password: lee

[root@docker harbor]# ./install.sh --help

Note: Please set hostname and other necessary attributes in harbor.yml first. DO NOT use localhost or 127.0.0.1 for hostname, because Harbor needs to be accessed by external clients.

#证书签名
Please set --with-notary if needs enable Notary in Harbor, and set ui_url_protocol/ssl_cert/ssl_cert_key in harbor.yml bacause notary must run under https. 

#安全扫描

Please set --with-trivy if needs enable Trivy in Harbor
Please set --with-chartmuseum if needs enable Chartmuseum in Harbor
[root@docker harbor]# 

[root@docker harbor]# ./install.sh --with-chartmuseum

[Step 0]: checking if docker is installed ...

Note: docker version: 27.2.0

[Step 1]: checking docker-compose is installed ...

Note: Docker Compose version v2.29.2

[Step 2]: loading Harbor images ...


✔ ----Harbor has been installed and started successfully.----

# 管理 harbor 的容器
[root@localhost harbor]# docker compose stop
✔ Container harbor-jobservice  Stopped                       0.1s
[root@localhost harbor]# docker compose down 
✔ Container harbor-jobservice        Removed                 0.1s
[root@localhost harbor]# docker compose up -d
✔ Network harbor_harbor              Created                 0.1s

注意:要打开windows中C:\Windows\System32\drivers\etc\hosts,输入你的IP地址和你在认证中填写的DNS中的名称

4.4.2 管理仓库

1. 登陆
2. 建立仓库项目

上传镜像

注意:

[root@localhost harbor]# cat /etc/docker/daemon.json
{
    "insecure-registries":["reg.timinglee.org"]              #这个是必须加的,要不然会登陆不进去
}
[root@localhost harbor]# 

[root@localhost harbor]# docker login reg.timinglee.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 harbor]# docker tag busybox:latest  reg.timinglee.org/timinglee/busybox:latest
[root@localhost harbor]# docker push reg.timinglee.org/timinglee/busybox:latest 
The push refers to repository [reg.timinglee.org/timinglee/busybox]
d51af96cf93e: Pushed 
latest: digest: sha256:28e01ab32c9dbcbaae96cf0d5b472f22e231d9e603811857b295e61197e40a9b size: 527
查看上传的镜像

Docker 网络

docker 的镜像是令人称道的地方,但网络功能还是相对薄弱的部分
docker 安装后会自动创建 3 种网络: bridge host none

[root@localhost ~]# docker network ls
NETWORK ID     NAME                        DRIVER    SCOPE
2a3c27034787   bridge                      bridge    local
21e338682b69   host                        host      local
9a816613ba83   none                        null      local

5.1 docker原生bridge网路


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

[root@docker ~]# 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:e8:a6:bc:d8 brd ff:ff:ff:ff:ff:ff

  • bridge模式下容器没有一个公有ip,只有宿主机可以直接访问,外部主机是不可见的。
  • 容器通过宿主机的NAT规则后可以访问外网

[root@docker ~]# docker run -d --name web -p 80:80 nginx:1.23 
fcbb923aa08aed33452e9ca9576ba9dedb82980e8f81f9218ca4a43dc82f91c5

[root@docker ~]# ifconfig 
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        inet6 fe80::42:e8ff:fea6:bcd8  prefixlen 64  scopeid 0x20<link>
        ether 02:42:e8:a6:bc:d8  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 34  bytes 4535 (4.4 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.10.110  netmask 255.255.255.0  broadcast 192.168.10.255
        inet6 fe80::1679:98d1:a5be:abe6  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:bd:9c:c3  txqueuelen 1000  (Ethernet)
        RX packets 535  bytes 44308 (43.2 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 531  bytes 68693 (67.0 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 17  bytes 2045 (1.9 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 17  bytes 2045 (1.9 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

vethaa7cd55: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::c4d9:6cff:fe39:2141  prefixlen 64  scopeid 0x20<link>
        ether c6:d9:6c:39:21:41  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 18  bytes 2352 (2.2 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

vethaa7cd55为容器使用的网卡

[root@docker mnt]# brctl show
bridge                    name bridge id                         STP enabled i                nterfaces
docker0                 8000.02425fe2346c                 no                                   veth022a7c9

5.2 docker原生网络host

host 网络模式需要在容器创建时指定 --network=host
host 模式可以让容器共享宿主机网络栈,这样的好处是外部主机与容器直接通信,但是容器的网络缺少隔离性

[root@docker ~]# docker run -it --name test --network host busybox:latest 
/ # ifconfig 
docker0   Link encap:Ethernet  HWaddr 02:42:3B:C2:FE:F1  
          inet addr:172.17.0.1  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST MULTICAST  MTU:1500  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:0 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

eth0      Link encap:Ethernet  HWaddr 00:0C:29:BD:9C:C3  
          inet addr:192.168.10.110  Bcast:192.168.10.255  Mask:255.255.255.0
          inet6 addr: fe80::1679:98d1:a5be:abe6/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:665 errors:0 dropped:0 overruns:0 frame:0
          TX packets:527 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:59452 (58.0 KiB)  TX bytes:78784 (76.9 KiB)

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:16 errors:0 dropped:0 overruns:0 frame:0
          TX packets:16 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:1995 (1.9 KiB)  TX bytes:1995 (1.9 KiB)

/ # 

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

5.3 docker 原生网络none


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

[root@docker ~]# docker run -it --name test --rm --network none busybox
/ # ifconfig 
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)

/ # 

5.4 docker的自定义网络


自定义网络模式, docker 提供了三种自定义网络驱动:
  • bridge
  • overlay
  • macvlan
bridge 驱动类似默认的 bridge 网络模式,但增加了一些新的功能,
overlay macvlan 是用于创建跨主机网络
建议使用自定义的网络来控制哪些容器可以相互通信,还可以自动 DNS 解析容器名称到 IP 地址。

5.4.1 自定义桥接网络

在建立自定以网络时,默认使用桥接模式
[root@docker ~]# docker network create mynet
7ae081e4248b36733a44fd1e72efca90678aa1a3d1e98e78d6d720ad2a09ac50
[root@docker ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
42822ed3287d   bridge    bridge    local
d539c11ef05f   host      host      local
7ae081e4248b   mynet     bridge    local
8f58cdd9eaff   none      null      local
桥接默认是单调递增

[root@docker ~]# ifconfig 
br-7ae081e4248b: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.18.0.1  netmask 255.255.0.0  broadcast 172.18.255.255
        ether 02:42:d5:9e:68:4f  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:3b:c2:fe:f1  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

桥接也支持自定义子网和网关
[root@docker ~]# docker network create mynet2 --subnet 192.168.0.0/
24 --gateway 192.168.0.100
562ecd991e1b38d13699d624898dbbd650fc905ee4e17aadf14c5fb0f857ebc6
[root@docker ~]# docker network inspect mynet2
[
    {
        "Name": "mynet2",
        "Id": "562ecd991e1b38d13699d624898dbbd650fc905ee4e17aadf14c5fb0f857ebc6",
        "Created": "2024-09-03T16:43:50.387822199+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.168.0.0/24",
                    "Gateway": "192.168.0.100"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]
[root@docker ~]#

5.4.2 为什么要自定义桥接

多容器之间如何互访?通过ip可以,但是有什么问题?

[root@docker ~]# docker run -d --name web1 nginx
c033992c955a72a06a7410ef42a8a9add2b7ed92d45a4dded01ada6b86776940
[root@docker ~]# docker run -d --name web2 nginx
f977b0cb25c916c39004dd9592cac5394de140a76716a7eaaee31ff0fa08beb0
 [root@docker ~]# docker inspect web1

"Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "MacAddress": "02:42:ac:11:00:02",
                    "DriverOpts": null,
                    "NetworkID": "42822ed3287dc9419e3d60dffe9795971199529a52bad6ec4e04701a826fa747",
                    "EndpointID": "65949d26ffbdde9a3e4a6961bdd3414c80804cfe850e093992037881f020f493",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.2",        #注意ip信息
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "DNSNames": null
[root@docker ~]# docker inspect web2
 "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "MacAddress": "02:42:ac:11:00:03",
                    "DriverOpts": null,
                    "NetworkID": "42822ed3287dc9419e3d60dffe9795971199529a52bad6ec4e04701a826fa747",
                    "EndpointID": "7e4246a50f918114e497964e7bbae66806690b6219fec6ec12011a1224f106de",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.3",        #注意ip信息
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "DNSNames": null

# 关闭容器后重启容器,启动顺序调换
[root@docker ~]# docker stop web1 web2
web1
web2
[root@docker ~]# docker start web2
web2
[root@docker ~]# docker start web1
web1
# 我们会发现容器 ip 颠倒
docker 引擎在分配 ip 时时根据容器启动顺序分配到,谁先启动谁用,是动态变更的
多容器互访用 ip 很显然不是很靠谱,那么多容器访问一般使用容器的名字访问更加稳定
docker 原生网络是不支持 dns 解析的,自定义网络中内嵌了 dns

[root@docker ~]# docker rm -f $(docker ps -aq)        #删除所有容器
f977b0cb25c9
c033992c955a
[root@docker ~]# docker ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

[root@docker ~]# docker run -d --network mynet --name web nginx
c4a967734d7fd15426314e80598e2b3e51c0575ddebe8c68dfc548748b3e91fb
[root@docker ~]# docker run -it --network mynet --name test busybox/ # ping web
PING web (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.169 ms
64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.139 ms
64 bytes from 172.18.0.2: seq=2 ttl=64 time=0.132 ms
^C
--- web ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.132/0.146/0.169 ms
/ #

注意:不同的自定义网络是不能通讯的
# rhel7 中使用的是 iptables 进行网络隔离,在 rhel9 中使用 nftpables
[root@docker ~]# nft list ruleset        # 可以看到网络隔离策略

5.4.3 如何让不同的自定义网络互通?

[root@docker ~]# docker run -d --network mynet --name web nginx
f37357bc8105dab19ede25853aad53a932676f972ad231bf72092e9bcee1c65f
[root@docker ~]# docker run -it --network mynet2 --name test busybox
/ # ifconfig 
eth0      Link encap:Ethernet  HWaddr 02:42:C0:A8:00:01  
          inet addr:192.168.0.1  Bcast:192.168.0.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:35 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:5194 (5.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)

/ # ping 172.18.0.2
PING 172.18.0.2 (172.18.0.2): 56 data bytes
^C
--- 172.18.0.2 ping statistics ---
7 packets transmitted, 0 packets received, 100% packet loss

[root@docker ~]# docker network connect mynet test
#在上面test容器中加入网络eth0

[root@docker ~]# docker attach test 
/ # 
/ # 
/ # ifconfig 
eth0      Link encap:Ethernet  HWaddr 02:42:AC:12:00:03  
          inet addr:172.18.0.3  Bcast:172.18.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:19 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:2302 (2.2 KiB)  TX bytes:0 (0.0 B)

eth1      Link encap:Ethernet  HWaddr 02:42:C0:A8:00:01  
          inet addr:192.168.0.1  Bcast:192.168.0.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:21 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:2562 (2.5 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)

/ # 

5.4.4 joined容器网络

Joined 容器一种较为特别的网络模式, 在容器创建时使用 --network=container:vm1 指定。( vm1 指定的是运行的容器名)
处于这个模式下的 Docker 容器会共享一个网络栈,这样两个容器之间可以使用 localhost 高效快速通信.

[root@docker ~]# docker run -d --name web1 --network mynet nginx
e7f495ff2ab30a1b65b311d3a3478f703b768f18f0094d8971a5cc221876a1d5
[root@docker ~]# docker run -it --rm --network container:web1 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:18 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:2352 (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: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 ~]# docker run -d --name web1 --network mynet2 nginx
c098c56586db2e5e9919a6aa9bd1f8595c3e444fde2e4ecb34cdcca2c14b04be
[root@docker ~]# docker run -it --rm --network container:web1 centos:7 
[root@c098c56586db /]# curl localhost
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

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

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

5.4.5 joined网络示例演示

利用容器部署 phpmyadmin 管理 mysql
#首先先导入镜像
[root@docker packages]# docker load -i phpmyadmin-latest.tar.gz 
4cae4ea97049: Loading layer  3.584kB/3.584kB
7f0d23b78477: Loading layer  320.2MB/320.2MB
8f42af1dd50e: Loading layer   5.12kB/5.12kB
7285b46fc0b1: Loading layer  51.28MB/51.28MB
886076bbd0e5: Loading layer  9.728kB/9.728kB
fe49c1c8ccdc: Loading layer   7.68kB/7.68kB
c98461c57e2d: Loading layer  13.41MB/13.41MB
4646cbc7a84d: Loading layer  4.096kB/4.096kB
7183cf0cacbe: Loading layer  49.48MB/49.48MB
923288b71444: Loading layer   12.8kB/12.8kB
eb4f3a0b1a71: Loading layer  4.608kB/4.608kB
43cd9aa62af4: Loading layer  4.608kB/4.608kB
9f9985f7ecbd: Loading layer  9.134MB/9.134MB
25d63a36933d: Loading layer  6.656kB/6.656kB
13ccf69b5807: Loading layer  53.35MB/53.35MB
a65e8a0ad246: Loading layer  8.192kB/8.192kB
26f3cdf867bf: Loading layer  3.584kB/3.584kB
Loaded image: phpmyadmin:latest
[root@docker packages]# 
# 运行 phpmysql admin
[root@docker ~]# docker run -d --name mysqladmin --network mynet \
> -e PMA_ARBITRARY=1 \     
#允许 phpmyadmin 连接到任何主机            
> -p 80:80 phpmyadmin:latest        
# web 页面中可以手动输入数据库地址和端口
c497158f2e9c09132762691c7b5537ad46a21237d92763a4bf367d26a98c8922
[root@docker ~]# 

# 运行数据库
[root@docker ~]# docker run -d --name mysql \
> -e MYSQL_ROOT_PASSWORD='123' \        
# 设定数据库密码
> --network container:mysqladmin \         # 把数据库容器添加到 phpmyadmin 容器中
> mysql:5.7
588bb200b06b223bfea637d60712305b398fdf95498ccfcdd951713975a32424
[root@docker ~]# 

注意:

开启的phpmyadmin容器中是没有数据库的
这里填写的localhost:3306是因为mysql容器和phpmyadmin容器公用一个网络站

5.5. 容器内外网的访问

5.5.1 容器访问外网

  • rhel7中,docker访问外网是通过iptables添加地址伪装策略来完成容器网文外网
  • rhel7之后的版本中通过nftables添加地址伪装来访问外网

[root@docker ~]# iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
DOCKER     all  --  0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  192.168.0.0/24       0.0.0.0/0           
MASQUERADE  all  --  172.18.0.0/16        0.0.0.0/0           
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0           
MASQUERADE  tcp  --  172.18.0.2           172.18.0.2           tcp dpt:80        
# 内网访问外网策略

Chain DOCKER (2 references)
target     prot opt source               destination         
RETURN     all  --  0.0.0.0/0            0.0.0.0/0           
RETURN     all  --  0.0.0.0/0            0.0.0.0/0           
RETURN     all  --  0.0.0.0/0            0.0.0.0/0           
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:80 to:172.18.0.2:80

5.5.2 外网访问docker容器

端口映射 -p 本机端口 : 容器端口来暴漏端口从而达到访问效果
# 通过 docker-proxy 对数据包进行内转
[root@docker ~]# docker run -d --name webserver -p 80:80 nginx
[root@docker ~]# ps ax
16419 ?        Sl     0:00 /usr/bin/docker-proxy -proto tcp -host
  16424 ?        Sl     0:00 /usr/bin/docker-proxy -proto tcp -host
  16456 ?        Sl     0:00 /usr/bin/containerd-shim-runc-v2 -name
  16483 ?        Ss     0:00 nginx: master process nginx -g daemon 
  16537 ?        S      0:00 nginx: worker process
# 通过 dnat 策略来完成浏览内转

[root@docker ~]# iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
DOCKER     all  --  0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  192.168.0.0/24       0.0.0.0/0           
MASQUERADE  all  --  172.18.0.0/16        0.0.0.0/0           
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0           
MASQUERADE  tcp  --  172.17.0.2           172.17.0.2           tcp dpt:80

Chain DOCKER (2 references)
target     prot opt source               destination         
RETURN     all  --  0.0.0.0/0            0.0.0.0/0           
RETURN     all  --  0.0.0.0/0            0.0.0.0/0           
RETURN     all  --  0.0.0.0/0            0.0.0.0/0           
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:80 to:172.17.0.2:80

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

5.6 docker跨主机网络


在生产环境中,我们的容器不可能都在同一个系统中,所以需要容器具备跨主机通信的能力
  • 跨主机网络解决方案
  1. docker原生的overlaymacvlan
  2. 第三方的flannelweavecalico
  • 众多网络方案是如何与docker集成在一起的
  1. libnetwork docker容器网络库
  2. CNM Container Network Model)这个模型对容器网络进行了抽象

5.6.1 CNM Container Network Model

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

5.6.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 主机上各添加一块网卡,打开网卡混杂模式:
[root@docker ~]# ip link set eth1 promisc on
[root@docker ~]# ip link set up eth1
[root@docker ~]# ifconfig eth1
eth1: flags=4419<UP,BROADCAST,RUNNING,PROMISC,MULTICAST>  mtu 1500
        ether 00:0c:29:bd:9c:cd  txqueuelen 1000  (Ethernet)
        RX packets 76  bytes 7165 (6.9 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

注意:eth1这款网卡在vmware中要设定为仅主机模式

2. 添加 macvlan 网路
[root@docker ~]# docker network create \
> -d macvlan \
> --subnet 1.1.1.0/24 \
> --gateway 1.1.1.1 \
> -o parent=eth1 mancvlan1
4b9322cd255187c40161cb1bfb82c209aab12ed4a814deb13f4d465d49811b28
[root@docker ~]# 
3. 测试

[root@docker ~]# docker run -it --name busybox --network macvlan1 --ip 1.1.1.100 --rm busybox
/ # ping 1.1.1.200
PING 1.1.1.200 (1.1.1.200): 56 data bytes
64 bytes from 1.1.1.200: seq=0 ttl=64 time=0.063 ms
64 bytes from 1.1.1.200: seq=1 ttl=64 time=0.199 ms
64 bytes from 1.1.1.200: seq=2 ttl=64 time=0.099 ms
64 bytes from 1.1.1.200: seq=3 ttl=64 time=0.099 ms
^C
--- 1.1.1.200 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.063/0.115/0.199 ms
 

[root@docker ~]# docker run -it --name busybox --network macvlan1 --ip 1.1.1.200 --rm busybox
/ # 

Docker 数据卷管理及优化


Docker 数据卷是一个可供容器使用的特殊目录,它绕过了容器的文件系统,直接将数据存储在宿主机上。
这样可以实现以下几个重要的目的:
  • 数据持久化:即使容器被删除或重新创建,数据卷中的数据仍然存在,不会丢失。
  • 数据共享:多个容器可以同时挂载同一个数据卷,实现数据的共享和交互。
  • 独立于容器生命周期:数据卷的生命周期独立于容器,不受容器的启动、停止和删除的影响。

6.1 为什么要用数据卷


docker 分层文件系统
  • 性能差
  • 生命周期与容器相同
docker 数据卷
  • mount到主机中,绕开分层文件系统
  • 和主机磁盘性能相同,容器删除后依然保留
  • 仅限本地磁盘,不能随容器迁移
docker 提供了两种卷:
  • bind mount
  • docker managed volume

6.2 bind mount 数据卷

  • 是将主机上的目录或文件mount到容器里。
  • 使用直观高效,易于理解。
  • 使用 -v 选项指定路径,格式 :
  • -v选项指定的路径,如果不存在,挂载时会自动创建
示例:
[root@docker ~]# docker run -it --rm \
> -v /tmp/data1:/data1 \
> -v /tmp/data1:/data2:ro \
> -v /etc/passwd:/data/passwd:ro busybox
/ # tail -n 3 /data/passwd 
systemd-oom:x:978:978:systemd Userspace OOM Killer:/:/usr/sbin/nologin
jin:x:1000:1000:jin:/home/jin:/bin/bash
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
/ # touch /data1/leefile1
/ # touch /data2/leefile1
touch: /data2/leefile1: Read-only file system
/ # 

6.3 docker managed 数据卷


  • bind mount必须指定host文件系统路径,限制了移植性
  • docker managed volume 不需要指定mount源,docker自动为容器创建数据卷目录
  • 默认创建的数据卷目录都在 /var/lib/docker/volumes
  • 如果挂载时指向容器内已有的目录,原有数据会被复制到volume
示例:
[root@docker ~]# docker volume prune        #清理未使用的数据卷
[root@docker ~]# docker run -d --name mysql -e MYSQL_ROOT_PASSWORD='123' mysql:5.7 
4eaeaf9752800fbb2ee8b6074acd40411aa1397232456e8a8e00e41d44af22fd
[root@docker ~]# ls -l /var/lib/docker/volumes/
total 32
brw------- 1 root root 253, 0 Sep  3 16:30 backingFsBlockDev
drwx-----x 3 root root     19 Sep  3 19:17 fb933a7186fe7709d022212aa9a31ca505190946d3782e852b4b9c452e7cd654
-rw------- 1 root root  65536 Sep  3 19:17 metadata.db
 
[root@docker ~]# cd /var/lib/docker/volumes/
[root@docker volumes]# cd fb933a7186fe7709d022212aa9a31ca505190946d3782e852b4b9c452e7cd654/
[root@docker fb933a7186fe7709d022212aa9a31ca505190946d3782e852b4b9c452e7cd654]# ls
_data
[root@docker fb933a7186fe7709d022212aa9a31ca505190946d3782e852b4b9c452e7cd654]# cd _data/
[root@docker _data]# touch hahafile
[root@docker _data]# docker exec -it mysql bash
bash-4.2# cd /var/lib/mysql
bash-4.2# ls
auto.cnf     ib_logfile0         private_key.pem
ca-key.pem     ib_logfile1         public_key.pem
ca.pem         ibdata1         server-cert.pem
client-cert.pem  ibtmp1             server-key.pem
client-key.pem     mysql             sys
hahafile     mysql.sock
ib_buffer_pool     performance_schema
bash-4.2#
清理未使用的 Docker 数据卷
[root@docker ~]# docker volume prune

注意:

1. 在执行 docker volume prune 命令之前,请确保你确实不再需要这些数据卷中的数据,因为
该操作是不可逆的,一旦删除数据将无法恢复。
2. 如果有重要的数据存储在数据卷中,建议先进行备份,或者确保数据已经被妥善保存到其他地
方。
建立数据卷

[root@docker ~]# docker volume create myo1
myo1
[root@docker ~]# ls -l /var/lib/docker/volumes/myo1/_data/
total 0

查看卷
[root@docker ~]# docker volume ls
DRIVER    VOLUME NAME
local     fb933a7186fe7709d022212aa9a31ca505190946d3782e852b4b9c452e7cd654
local     myo1
使用建立的数据卷
[root@docker ~]# docker run -d --name web1 -p 80:80 -v myo1:/usr/share/nginx/html nginx
21a00e40e618cbe7df3dd73fcc9aff38d7b42c1e89fd63a13c5c9d0c0b32106d
[root@docker ~]# cd /var/lib/docker/volumes/myo1/_data/
[root@docker _data]# ls
[root@docker _data]# echo hello > index.html
[root@docker _data]# curl 192.168.10.110
hello

6.4 数据卷容器(Data Volume Container

数据卷容器( Data Volume Container )是 Docker 中一种特殊的容器,主要用于方便地在多个容器之间共享数据卷。
1. 建立数据卷容器
[root@docker ~]# 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 ~]# docker run -d --name datavol \
-v /tmp/data1:/data1:rw \
-v /tmp/data2:/data2:ro \
-v /etc/resolv.conf:/etc/hosts busybox
b7168f0d99674714565d26b68f70a23bdbe1ff9278a165f6408ca2141fa97020
[root@docker ~]#  docker run -it --name test --rm --volumes-from datavol busybox
/ # ls
bin    data2  etc    lib    proc   sys    usr
data1  dev    home   lib64  root   tmp    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 com

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

6.5 bind mount 数据卷和docker managed 数据卷的对

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

6.6 备份与迁移数据卷

备份数据卷
# 建立容器并指定使用卷到要备份的容器
[root@docker ~]# docker run -it --name test --rm -v test:/data busybox
/ # ls
bin    dev    home   lib64  root   tmp    var
data   etc    lib    proc   sys    usr
/ # cd data/
/data # ls
/data # touch xixi
/data # touch opq
/data # ls
opq   xixi
/data #               
#按ctrl+p+q
[root@docker ~]#                 
[root@docker ~]# docker run -it --volumes-from test -v `pwd`:/backup --rm --name test1 busybox         # 把当前目录挂在到容器中用于和容器交互保存要备 份的容器
/ # ls
backup  data    etc     lib     proc    sys     usr
bin     dev     home    lib64   root    tmp     var
/ # ls /data/
opq   xixi
/ # tar zcf /backup/data1.tar.gz /data                 # 备份数据到本地
tar: removing leading '/' from member names
/ # 
#重新复制一个会话,查看
[root@docker ~]# ls
data1.tar.gz
数据恢复
[root@docker ~]# docker run -it --name test -v test:/data -v `pwd`:/backup busybox /bin/sh -c "tar zxf /backup/data1.tar.gz;/bin/sh"
/ # cd data/
/data # ls         # 查看数据迁移情况
opq   xixi
/data # 

Docker 的安全优化

Docker 容器的安全性,很大程度上依赖于 Linux 系统自身
评估 Docker 的安全性时,主要考虑以下几个方面:
  • Linux内核的命名空间机制提供的容器隔离安全
  • Linux控制组机制对容器资源的控制能力安全。
  • Linux内核的能力机制所带来的操作权限安全
  • Docker程序(特别是服务端)本身的抗攻击性。
  • 其他安全增强机制对容器安全性的影响
# rhel9 中默认使用 cgroup-v2 但是 cgroup-v2 中不利于观察 docker 的资源限制情况,所以推荐使用cgroup-v1
[root@docker ~]#  grubby --update-kernel=/boot/vmlinuz-$(uname -r) \
--args="systemd.unified_cgroup_hierarchy=0
systemd.legacy_systemd_cgroup_controller"
[root@docker ~]# reboot
[root@docker ns]# mount -t cgroup
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
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/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/misc type cgroup (rw,nosuid,nodev,noexec,relatime,misc)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
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)
1 命名空间隔离的安全
  • docker run启动一个容器时,Docker将在后台为容器创建一个独立的命名空间。命名空间提供了最基础也最直接的隔离。
  • 与虚拟机方式相比,通过Linux namespace来实现的隔离不是那么彻底。
  • 容器只是运行在宿主机上的一种特殊的进程,那么多个容器之间使用的就还是同一个宿主机的操作系统内核。
  • Linux 内核中,有很多资源和对象是不能被 Namespace 化的,比如:磁盘等等

[root@docker ~]# docker run -d --name web nginx
23f6af8121018d6f1a329ec279b4e79bb87656549c2b9c4a53e6e974921fecd3

[root@docker ~]# docker inspect web | grep Pid
                "Pid": 2949,
            "PidMode": "",
            "PidsLimit": null,


[root@docker ~]# cd /proc/2949/ns/                #进程的namespace
[root@docker ns]# ls
cgroup  mnt  pid               time               user
ipc     net  pid_for_children  time_for_children  uts

[root@docker ~]# ls -d /sys/fs/cgroup/memory/docker/23f6af8121018d6f1a329ec279b4e79bb87656549c2b9c4a53e6e974921fecd3/    #资源隔离信息
/sys/fs/cgroup/memory/docker/23f6af8121018d6f1a329ec279b4e79bb87656549c2b9c4a53e6e974921fecd3/

2 控制组资源控制的安全
  • docker run启动一个容器时,Docker将在后台为容器创建一个独立的控制组策略集合。
  • Linux Cgroups提供了很多有用的特性,确保各容器可以公平地分享主机的内存、CPU、磁盘IO资源。
  • 确保当发生在容器内的资源压力不会影响到本地主机系统和其他容器,它在防止拒绝服务攻击 DDoS)方面必不可少

[root@docker ~]# docker run -it --name test busybox
/ # free -m
              total        used        free      shared  buff/cache   available
Mem:           1744         753         334          12         657         818
Swap:          2048           0        2048
/ # exit
[root@docker ~]# free -m
               total        used        free      shared  buff/cache   available
Mem:            1743         867         391          11         657         876
Swap:           2047           0        2047

3 内核能力机制
  • 能力机制(Capability)是Linux内核一个强大的特性,可以提供细粒度的权限访问控制。
  • 大部分情况下,容器并不需要真正的”root权限,容器只需要少数的能力即可。
  • 默认情况下,Docker采用白名单机制,禁用必需功能之外的其他权限。
4 Docker 服务端防护
  • 使用Docker容器的核心是Docker服务端,确保只有可信的用户才能访问到Docker服务。
  • 将容器的root用户映射到本地主机上的非root用户,减轻容器和主机之间因权限提升而引起的安全问题。
  • 允许Docker 服务端在非root权限下运行,利用安全可靠的子进程来代理执行需要特权权限的操作。这些子进程只允许在特定范围内进行操作。

[root@docker ~]# ls -ld /var/lib/docker/                #默认docker是用root用户控制资源的
drwx--x--- 12 root root 171 Sep  4 09:02 /var/lib/docker/

7.1 Docker的资源限制

Linux Cgroups 的全称是 Linux Control Group
  • 是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等。
  • 对进程进行优先级设置、审计,以及将进程挂起和恢复等操作。
Linux Cgroups 给用户暴露出来的操作接口是文件系统
  • 它以文件和目录的方式组织在操作系统的 /sys/fs/cgroup 路径下。
  • 执行此命令查看:mount -t cgroup

[root@docker ~]# mount -t cgroup                #在rhel9中默认使用cgroup2
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd)
cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/misc type cgroup (rw,nosuid,nodev,noexec,relatime,misc)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
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/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)

  • /sys/fs/cgroup 下面有很多诸如 cpusetcpu memory 这样的子目录,也叫子系统。
  • 在每个子系统下面,为每个容器创建一个控制组(即创建一个新目录)。
  • 控制组下面的资源文件里填上什么值,就靠用户执行 docker run 时的参数指定。

7.1.1.限制cpu使用

1. 限制 cpu 的使用量

[root@docker ~]# docker run -it --rm --name test --cpu-period 100000 --cpu-quota 20000 ubuntu
root@2f78e8e83ad6:/# dd if=/dev/zero of=/dev/null &
[1] 8
root@2f78e8e83ad6:/# top
top - 01:18:34 up 16 min,  0 user,  load average: 0.00, 0.
Tasks:   3 total,   2 running,   1 sleeping,   0 stopped, 
%Cpu(s):  7.5 us, 11.0 sy,  0.0 ni, 80.8 id,  0.0 wa,  0.3
MiB Mem :   1743.7 total,    115.9 free,    966.1 used,   
MiB Swap:   2048.0 total,   2048.0 free,      0.0 used.   

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU 
      8 root      20   0    2736   1116   1028 R  20.0 
#使用cpu的百分比 

    1 root      20   0    4588   4132   3532 S   0.0 
      9 root      20   0    8872   5280   3160 R   0.0

# cgroup 中查看 docker 的资源限制
[root@docker ~]# cat /sys/fs/cgroup/cpu/docker/87c64648cc9b8724b91cbb9b1646334150e341a693aeb77fef76928684ef4741/cpu.cfs_quota_us 
20000
2. 限制 cpu 的优先级
# 关闭 cpu 的核心,当 cpu 都不空闲下才会出现争抢的情况,为了实验效果我们可以关闭一个 cpu 核心,如果只有一个那就不需要关闭cpu的核心
[root@docker ~]# echo 0 > /sys/devices/system/cpu/cpu1/online 
[root@docker ~]# cat /proc/cpuinfo 
processor    : 0
vendor_id    : GenuineIntel
cpu family    : 6
model        : 140
model name    : 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz
stepping    : 1
microcode    : 0x86
cpu MHz        : 2419.211
cache size    : 8192 KB
physical id    : 0
siblings    : 1
core id        : 0
cpu cores    : 1                
#cpu 核心数为 1
apicid        : 0
initial apicid    : 0
fpu        : yes
fpu_exception    : yes
cpuid level    : 27
wp        : yes
flags        : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology tsc_reliable nonstop_tsc cpuid tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat avx512vbmi umip pku ospke avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq rdpid movdiri movdir64b fsrm avx512_vp2intersect md_clear flush_l1d arch_capabilities
bugs        : spectre_v1 spectre_v2 spec_store_bypass swapgs itlb_multihit eibrs_pbrsb
bogomips    : 4838.42
clflush size    : 64
cache_alignment    : 64
address sizes    : 45 bits physical, 48 bits virtual
power management:
# 开启容器并限制资源

[root@docker ~]# docker run -it --rm --cpu-shares 100 ubuntu
root@afdafc23549b:/# dd if=/dev/zero of=/dev/null &
[1] 9
root@afdafc23549b:/# top
top - 01:50:55 up 48 min,  0 user,  load average: 1.39, 0.
Tasks:   3 total,   2 running,   1 sleeping,   0 stopped, 
%Cpu(s): 57.1 us, 42.4 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.4
MiB Mem :   1743.7 total,     88.1 free,    989.5 used,   
MiB Swap:   2048.0 total,   2048.0 free,      0.0 used.   

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU 
      9 root      20   0    2736   1080    992 R   8.9 

#cpu有限制被限制
      1 root      20   0    4588   3892   3292 S   0.0 
     10 root      20   0    8872   5380   3264 R   0.0

# 开启另外一个容器不限制 cpu 的优先级

[root@docker ~]# docker run -it --rm  ubuntu
root@b74832e3b34b:/# dd if=/dev/zero of=/dev/null &
[1] 9
root@b74832e3b34b:/# top
top - 01:50:49 up 48 min,  0 user,  load average: 1.34, 0.
Tasks:   3 total,   2 running,   1 sleeping,   0 stopped, 
%Cpu(s): 54.2 us, 45.4 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.4
MiB Mem :   1743.7 total,     88.1 free,    989.5 used,   
MiB Swap:   2048.0 total,   2048.0 free,      0.0 used.   

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU 
      9 root      20   0    2736   1052    964 R  90.7 

#cpu未被限制
      1 root      20   0    4588   4048   3452 S   0.0 
     10 root      20   0    8872   5276   3140 R   0.0

7.1.2 限制内存使用

# 开启容器并限制容器使用内存大小
[root@docker ~]# docker run -d --name test --memory 200M --memory-swap 200M nginx
8555d3b1059716e887e41da18c780c14abb4211460320d0a22585c678af22112
[root@docker ~]# cd /sys/fs/cgroup/memory/docker/8555d3b1059716e887e41da18c780c14abb4211460320d0a22585c678af22112/
[root@docker 8555d3b1059716e887e41da18c780c14abb4211460320d0a22585c678af22112]# cat memory.limit_in_bytes 
209715200
[root@docker 8555d3b1059716e887e41da18c780c14abb4211460320d0a22585c678af22112]# cat memory.memsw.limit_in_bytes 
209715200
# 测试容器内存限制,在容器中我们测试内存限制效果不是很明显,可以利用工具模拟容器在内存中写入数据
# 在系统中 /dev/shm 这个目录被挂在到内存中
[root@docker ~]# cd /sys/fs/cgroup/
[root@docker ~]# cgexec -g memory:docker/23087f2a5c2ea40b99e59178deb5d470bcb4fe26349197d010fd5eb43e956f31 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=180
180+0 records in
180+0 records out
188743680 bytes (189 MB, 180 MiB) copied, 0.0609634 s, 3.1 GB/s
[root@docker ~]# cgexec -g memory:docker/23087f2a5c2ea40b99e59178deb5d470bcb4fe26349197d010fd5eb43e956f31 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=120
120+0 records in
120+0 records out
125829120 bytes (126 MB, 120 MiB) copied, 0.0263904 s, 4.8 GB/s
[root@docker ~]# cgexec -g memory:docker/23087f2a5c2ea40b99e59178deb5d470bcb4fe26349197d010fd5eb43e956f31 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=200
Killed
 
# 也可以自建控制器
[root@docker ~]# mkdir -p /sys/fs/cgroup/memory/x1
[root@docker ~]# ls /sys/fs/cgroup/memory/x1
cgroup.clone_children
cgroup.event_control
cgroup.procs
memory.failcnt
memory.force_empty
memory.kmem.failcnt
memory.kmem.limit_in_bytes
memory.kmem.max_usage_in_bytes
memory.kmem.slabinfo
memory.kmem.tcp.failcnt
memory.kmem.tcp.limit_in_bytes
memory.kmem.tcp.max_usage_in_bytes
memory.kmem.tcp.usage_in_bytes
memory.kmem.usage_in_bytes
memory.limit_in_bytes
memory.max_usage_in_bytes
memory.memsw.failcnt
memory.memsw.limit_in_bytes
memory.memsw.max_usage_in_bytes
memory.memsw.usage_in_bytes
memory.move_charge_at_immigrate
memory.numa_stat
memory.oom_control
memory.pressure_level
memory.soft_limit_in_bytes
memory.stat
memory.swappiness
memory.usage_in_bytes
memory.use_hierarchy
notify_on_release
tasks

[root@docker ~]# echo 209715200 > /sys/fs/cgroup/memory/x1/memory.limit_in_bytes
         # 内存可用大小限制
[root@docker ~]# cat /sys/fs/cgroup/memory/x1/tasks     # 此控制器被哪个进程调用
[root@docker ~]# 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.0290131 s, 3.6 GB/s
[root@docker ~]# free -m
               total        used        free      shared  buff/cache   available
Mem:            1743        1025         170         113         828         718
Swap:           2047           8        2039
[root@docker ~]# 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.208428 s, 1.5 GB/s
[root@docker ~]# free -m
               total        used        free      shared  buff/cache   available
Mem:            1743        1125          70         206         921         618
Swap:           2047         115        1932           
# 内存溢出部分被写入 swap 交换分
[root@docker ~]# rm -rf /dev/shm/bigfile 
[root@docker ~]# echo 209715200 > /sys/fs/cgroup/memory/x1/memory.memsw.limit_in_bytes          # 内存 +swap 控制
[root@docker ~]# cgexec -g memory:x1 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=180
180+0 records in
180+0 records out
188743680 bytes (189 MB, 180 MiB) copied, 0.0508754 s, 3.7 GB/s
[root@docker ~]# 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.041449 s, 4.8 GB/s
[root@docker ~]# cgexec -g memory:x1 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=200
Killed
注意:
cgexec -g memory:doceker/容器id -g表示使用指定控制器类型

7.1.3 限制docker的磁盘io

[root@docker ~]# docker run -it --rm \
> --device-write-bps \                
#指定容器使用磁盘io的速率
> /dev/nvme0n1:30M \                #/dev/nvme0n1是指定系统的磁盘,30M即每秒30M数据
> ubuntu


root@7f655acccc5c:/# dd if=/dev/zero of=bigfile                #开启容器后会发现速度和设定不匹配,是因为系统的缓存机制


dd: writing to 'bigfile': No space left on device
3992529+0 records in
3992528+0 records out
2044174336 bytes (2.0 GB, 1.9 GiB) copied, 6.44758 s, 317 MB/s


root@7f655acccc5c:/# 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.0342619 s, 3.1 GB/s


root@7f655acccc5c:/# dd if=/dev/zero of=bigfile bs=1M count=100 oflag=direct        #设定dd命令直接写入磁盘
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 2.5442 s, 41.2 MB/s

7.2 Docker的安全加固

7.2.1 Docker默认隔离性

在系统中运行容器,我们会发现资源并没有完全隔离开
[root@docker ~]# free -m               # 系统内存使用情况  
               total        used        free      shared  buff/cache   available
Mem:            1743         833         622          10         459         910
Swap:           2047          42        2005
[root@docker ~]# docker run --rm --memory 200M -it ubuntu
root@fb59348e879a:/# free -m             # 容器中内存使用情况     
               total        used        free      shared  buff/cache   available
Mem:            1743         897         478          10         539         846
Swap:           2047          42        2005
# 虽然我们限制了容器的内容使用情况,但是查看到的信息依然是系统中内存的使用信息,并没有隔离开

7.2.2 解决Docker的默认隔离性

LXCFS 是一个为 LXC Linux Containers )容器提供增强文件系统功能的工具。
主要功能
        1. 资源可见性
  •         LXCFS 可以使容器内的进程看到准确的 CPU、内存和磁盘 I/O 等资源使用信息。在没有 LXCFS 时,容器内看到的资源信息可能不准确,这会影响到在容器内运行的应用程序对资源的评估和管理。
        2. 性能监控
  •         方便对容器内的资源使用情况进行监控和性能分析。通过提供准确的资源信息,管理员和开发人员可以更好地了解容器化应用的性能瓶颈,并进行相应的优化。
安装 lxcfs
# rhel9 lxcfs 是被包含在 epel 源中,我们可以直接下载安装包进行安装
[root@docker ~]# cd packages/
[root@docker packages]# cd rpm/
[root@docker rpm]# 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 rpm]# yum install lxc*.rpm -y
运行 lxcfs 并解决容器隔离性
[root@docker ~]# lxcfs /var/lib/lxcfs &
[root@docker ~]# docker run -it -m 256m \
> -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
root@545d93154bc3:/# free -m
               total        used        free      shared  buff/cache   available
Mem:             256           1         254           0           0         254
Swap:            512           0         512
root@545d93154bc3:/# 

7.2.3 容器特权

在容器中默认情况下即使我是容器的超级用户也无法修改某些系统设定,比如网络
[root@docker ~]# 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
7: eth0@if8: <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 a a 192.168.0.20/24 dev eth0@if8
ip: can't find device 'eth0@if8'
/ # ip a a 192.168.0.20/24 dev eth0
ip: RTNETLINK answers: Operation not permitted
这是因为容器使用的很多资源都是和系统真实主机公用的,如果允许容器修改这些重要资源,系统的稳定性会变的非常差
但是由于某些需要求,容器需要控制一些默认控制不了的资源,如何解决此问题,这时我们就要设置容器特权

[root@docker ~]# docker run --rm -it --privileged busybox
/ # id root
uid=0(root) gid=0(root) groups=0(root),10(wheel)
/ # ip a a 192.168.0.100/24 dev eth0
/ # 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
9: eth0@if10: <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
    inet 192.168.0.100/24 scope global eth0
       valid_lft forever preferred_lft forever
/ # fdisk -l
Disk /dev/nvme0n1: 20 GB, 21474836480 bytes, 41943040 sectors
82241 cylinders, 255 heads, 2 sectors/track
Units: sectors of 1 * 512 = 512 bytes

Device       Boot StartCHS    EndCHS        StartLBA     EndLBA    Sectors  Size Id Type
/dev/nvme0n1p1 *  4,4,1       1023,254,2        2048    2099199    2097152 1024M 83 Linux
/dev/nvme0n1p2    1023,254,2  1023,254,2     2099200   41943039   39843840 18.9G 8e Linux LVM
Disk /dev/dm-0: 17 GB, 18249416704 bytes, 35643392 sectors
2218 cylinders, 255 heads, 63 sectors/track
Units: sectors of 1 * 512 = 512 bytes

Disk /dev/dm-0 doesn't contain a valid partition table
Disk /dev/dm-1: 2048 MB, 2147483648 bytes, 4194304 sectors
261 cylinders, 255 heads, 63 sectors/track
Units: sectors of 1 * 512 = 512 bytes

Disk /dev/dm-1 doesn't contain a valid partition table
/ #

# 如果添加了 --privileged 参数开启容器,容器获得权限近乎于宿主机的 root 用户

7.2.4 容器特权的白名单

--privileged=true 的权限非常大,接近于宿主机的权限,为了防止用户的滥用,需要增加限制,只提供给容器必须的权限。此时Docker 提供了权限白名单的机制,使用 --cap-add 添加必要的权限
capabilities 手册地址: http://man7.org/linux/man-pages/man7/capabilities.7.html
# 限制容器对网络有 root 权限
[root@docker ~]# docker run --rm -it --cap-add NET_ADMIN busybox
/ # ip a a 192.168.0.20/24 dev eth0                
# 网络可以设定
/ # 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
11: eth0@if12: <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
    inet 192.168.0.20/24 scope global eth0
       valid_lft forever preferred_lft forever
/ # fdisk -l                                
# 无法管理磁盘

容器编排工具Docker Compose

8.1 Docker Compose 概述

Docker Compose 是一个用于定义和运行多容器 Docker 应用程序的工具。
其是官方的一个开源项目,托管到 github
网址: https://github.com/docker/compose
主要功能
1. 定义服务
  • 使用 YAML 格式的配置文件来定义一组相关的容器服务。每个服务可以指定镜像、端口映射、环境变量、存储卷等参数。
  • 例如,可以在配置文件中定义一个 Web 服务和一个数据库服务,以及它们之间的连接关系。
2. 一键启动和停止
  • 通过一个简单的命令,可以启动或停止整个应用程序所包含的所有容器。这大大简化了多容器应用的部署和管理过程。
  • 例如,使用 docker-compose up 命令可以启动配置文件中定义的所有服务,使用 docker-compose down 命令可以停止并删除这些服务。
3. 服务编排
  • 可以定义容器之间的依赖关系,确保服务按照正确的顺序启动和停止。例如,可以指定数据库服务必须在 Web 服务之前启动。
  • 支持网络配置,使不同服务的容器可以相互通信。可以定义一个自定义的网络,将所有相关的容器连接到这个网络上。
4. 环境变量管理
  • 可以在配置文件中定义环境变量,并在容器启动时传递给容器。这使得在不同环境(如开发、测试和生产环境)中使用不同的配置变得更加容易。
  • 例如,可以定义一个数据库连接字符串的环境变量,在不同环境中可以设置不同的值。
工作原理
1. 读取配置文件
  • Docker Compose 读取 YAML 配置文件,解析其中定义的服务和参数。
2. 创建容器
  • 根据配置文件中的定义,Docker Compose 调用 Docker 引擎创建相应的容器。它会下载所需的镜像(如果本地没有),并设置容器的各种参数。
3. 管理容器生命周期
  • Docker Compose 监控容器的状态,并在需要时启动、停止、重启容器。
  • 它还可以处理容器的故障恢复,例如自动重启失败的容器。
Docker Compose 中的管理层
1. 服务 (service) 一个应用的容器,实际上可以包括若干运行相同镜像的容器实例
2. 项目 (project) 由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义
3. 容器( container )容器是服务的具体实例,每个服务可以有一个或多个容器。容器是基于服务定义的镜像创建的运行实例

8.2 Docker Compose 的常用命令参数

[root@docker ~]# cat test/compose.yml
#version: "1.0"
services:
  web:
    image: nginx
    ports:
      - "80:80"
    db:
      image: mysql:5.7
      environment:
        MYSQL_ROOT_PASSWORD: lee
以下是一些 Docker Compose 常用命令:
一、服务管理
1. docker compose up
  • 启动配置文件中定义的所有服务。
  • 可以使用 -d 参数在后台启动服务。
  • 可以使用-f 来指定yml文件
  • 例如: docker-compose up -d

[root@docker test]# docker compose up -d
[+] Running 1/1
 ✔ Container test-web-1  Started                             0.3s

[root@docker ~]# docker compose -f test/docker-compose.yml up -d
[+] Running 3/3
 ✔ Network test_default  Created                             0.1s
 ✔ Container test-db-1   Started                             0.4s 
 ✔ Container test-web-1  Started                             0.5s

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

[root@docker test]# docker compose down 
[+] Running 3/3
 ✔ Container test-web-1  Removed                             0.1s 
 ✔ Container test-db-1   Removed                             1.6s 
 ✔ Network test_default  Removed                             0.1s

3. docker compose start
  • 启动已经存在的服务,但不会创建新的服务。

[root@docker test]# docker compose start 
[+] Running 2/2
 ✔ Container test-db-1   Started                             0.4s 
 ✔ Container test-web-1  Started                             0.5s

4. docker compose stop
  • 停止正在运行的服务

[root@docker test]# docker compose stop
[+] Stopping 2/2
 ✔ Container test-db-1   Stopped                             1.8s 
 ✔ Container test-web-1  Stopped                             0.1s

5. docker compose restart
  • 重启服务。

[root@docker test]# docker compose restart 
[+] Restarting 2/2
 ✔ Container test-web-1  Started                             0.5s 
 ✔ Container test-db-1   Started                             0.4s

8.3 服务状态查看

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

[root@docker test]# docker compose ps
NAME         IMAGE       COMMAND                  SERVICE   CREATED         STATUS         PORTS
test-db-1    mysql:5.7   "docker-entrypoint.s…"   db        4 minutes ago   Up 2 minutes   3306/tcp, 33060/tcp
test-web-1   nginx       "/docker-entrypoint.…"   web       4 minutes ago   Up 2 minutes   0.0.0.0:80->80/tcp, :::80->80/tcp

2. docker compose logs
  • 查看服务的日志输出。可以指定服务名称来查看特定服务的日志。

[root@docker test]# docker compose logs web 

8.4 构建和重新构建服务(了解)

1. docker compose build
  • 构建配置文件中定义的服务的镜像。可以指定服务名称来只构建特定的服务。

[root@docker test]# cat Dockerfile
FROM busybox:latest
RUN touch /leefile1

[root@docker test]# cat xixi.Dockerfile 
FROM nginx:latest
RUN touch /leefile
 

[root@docker test]# cat test.yml 
services:
  test1:
    image: test1                        #生成镜像名称
    build:
      context: /root/test                        #指定Dockerfile位置
      dockerfile: xixi.Dockerfile                #指定Dockerfile名字
    command: ["/bin/sh","-c","sleep 3000"]
    restart: always
    container_name: busybox1

  test2:
    image: test2
    build:
      context: /root/test
      dockerfile: Dockerfile
    command: ["/bin/sh","-c","sleep 3000"]
    restart: always
    container_name: busybox2

[root@docker test]# docker compose -f test.yml build        #构建services中的所有

[+] Building 0.6s (14/14) FINISHED                 docker:default
 => [test2 internal] load build definition from Dockerfile   0.0s
 => => transferring dockerfile: 77B                          0.0s
 => [test1 internal] load build definition from xixi.Docker  0.0s
 => => transferring dockerfile: 79B                          0.0s
 => [test1 internal] load metadata for docker.io/library/ng  0.0s
 => [test1 internal] load .dockerignore                      0.0s
 => => transferring context: 2B                              0.0s
 => [test2 internal] load metadata for docker.io/library/bu  0.0s
 => [test2 internal] load .dockerignore                      0.0s
 => => transferring context: 2B                              0.0s
 => CACHED [test1 1/2] FROM docker.io/library/nginx:latest   0.0s
 => [test1 2/2] RUN touch /leefile                           0.3s
 => CACHED [test2 1/2] FROM docker.io/library/busybox:lates  0.0s
 => [test2 2/2] RUN touch /leefile1                          0.4s
 => [test1] exporting to image                               0.1s
 => => exporting layers                                      0.1s
 => => writing image sha256:bbed0fad2bf80457722e916ca3c13d1  0.0s
 => => naming to docker.io/library/test1                     0.0s
 => [test2] exporting to image                               0.0s
 => => exporting layers                                      0.0s
 => => writing image sha256:2c790a2ff55f1536907b265bcd4d4d8  0.0s
 => => naming to docker.io/library/test2                     0.0s
 => [test1] resolving provenance for metadata file           0.0s
 => [test2] resolving provenance for metadata file           0.0s

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

[+] Building 0.1s (7/7) FINISHED                   docker:default
 => [test1 internal] load build definition from xixi.Docker  0.0s
 => => transferring dockerfile: 79B                          0.0s
 => [test1 internal] load metadata for docker.io/library/ng  0.0s
 => [test1 internal] load .dockerignore                      0.0s
 => => transferring context: 2B                              0.0s
 => [test1 1/2] FROM docker.io/library/nginx:latest          0.0s
 => CACHED [test1 2/2] RUN touch /leefile                    0.0s
 => [test1] exporting to image                               0.0s
 => => exporting layers                                      0.0s
 => => writing image sha256:bbed0fad2bf80457722e916ca3c13d1  0.0s
 => => naming to docker.io/library/test1                     0.0s
 => [test1] resolving provenance for metadata file           0.0s

2. docker compose up --build
  • 启动服务并在启动前重新构建镜像。

[root@docker test]# docker compose -f test.yml up -d        #会去仓库拉去镜像

[+] Running 2/2
 ✔ Container busybox1  Started                               0.4s 
 ✔ Container busybox2  Started                               0.4s 
[root@docker test]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS     NAMES
737df86cbfd8   test1     "/docker-entrypoint.…"   22 seconds ago   Up 22 seconds   80/tcp    busybox1
64cb0108017b   test2     "/bin/sh -c 'sleep 3…"   22 seconds ago   Up 22 seconds             busybox2

[root@docker test]# docker compose -f test.yml up --build        #会先构建镜像后启动容器

[+] Building 0.1s (14/14) FINISHED                 docker:default
 => [test1 internal] load build definition from xixi.Docker  0.0s
 => => transferring dockerfile: 79B                          0.0s
 => [test2 internal] load build definition from Dockerfile   0.0s
 => => transferring dockerfile: 77B                          0.0s
 => [test1 internal] load metadata for docker.io/library/ng  0.0s
 => [test1 internal] load .dockerignore                      0.0s
 => => transferring context: 2B                              0.0s
 => [test2 internal] load metadata for docker.io/library/bu  0.0s
 => [test2 internal] load .dockerignore                      0.0s
 => => transferring context: 2B                              0.0s
 => [test2 1/2] FROM docker.io/library/busybox:latest        0.0s
 => [test1 1/2] FROM docker.io/library/nginx:latest          0.0s
 => CACHED [test1 2/2] RUN touch /leefile                    0.0s
 => CACHED [test2 2/2] RUN touch /leefile1                   0.0s
 => [test1] exporting to image                               0.0s
 => => exporting layers                                      0.0s
 => => writing image sha256:bbed0fad2bf80457722e916ca3c13d1  0.0s
 => => naming to docker.io/library/test1                     0.0s
 => [test2] exporting to image                               0.0s
 => => exporting layers                                      0.0s
 => => writing image sha256:2c790a2ff55f1536907b265bcd4d4d8  0.0s
 => => naming to docker.io/library/test2                     0.0s
 => [test1] resolving provenance for metadata file           0.0s
 => [test2] resolving provenance for metadata file           0.0s
[+] Running 2/0
 ✔ Container busybox2  Created                               0.0s 
 ✔ Container busybox1  Created                               0.0s 
Attaching to busybox1, busybox2
^CGracefully stopping... (press Ctrl+C again to force)
[+] Stopping 2/2
 ✔ Container busybox2  Stopped                              10.2s 
 ✔ Container busybox1  Stopped                              10.2s 
canceled

8.5 其他操作

1. docker compose exec
  • 在正在运行的服务容器中执行命令。

[root@docker test]# cat test.yml 
services:
  test:
    image: test1
    command: ["/bin/sh","-c","sleep 3000"]
    restart: always
    container_name: busybox1


[root@docker test]# docker compose -f test.yml exec test sh
# ls
bin   docker-entrypoint.d   home     lib64  opt   run    sys  var
boot  docker-entrypoint.sh  leefile  media  proc  sbin    tmp
dev   etc            lib      mnt    root  srv    usr

2. docker-compose pull
  • 拉取配置文件中定义的服务所使用的镜像。
[root@docker test]# docker compose -f test.yml pull       #Docker 镜像仓库中拉取镜像
[+] Pulling 2/2
test Pulled
ec562eabd705 Pull complete
3. docker-compose config
  • 验证并查看解析后的 Compose 文件内容

[root@docker test]# docker compose -f test.yml config 
name: test
services:
  test:
    command:
      - /bin/sh
      - -c
      - sleep 3000
    container_name: busybox1
    image: busybox
    networks:
      default: null
    restart: always
networks:
  default:
    name: test_default

8.6 Docker Compose yml文件

Docker Compose YAML 文件用于定义和配置多容器应用程序的各个服务。以下是一个基本的
Docker Compose YAML 文件结构及内容解释:

8.6.1 服务(services

1. 服务名称( service1_name/service2_name 等)
  • 每个服务在配置文件中都有一个唯一的名称,用于在命令行和其他部分引用该服务。
services:
        web:
                # 服务1 的配置
        mysql:
                # 服务2 的配置
2. 镜像( image
  • 指定服务所使用的 Docker 镜像名称和标签。例如, image: nginx:latest 表示使用 nginx镜像的最新版本
services:
        web:
                images:nginx
        mysql:
                images:mysql:5.7
3. 端口映射( ports
  • 将容器内部的端口映射到主机的端口,以便外部可以访问容器内的服务。例如, - "8080:80" 表示将主机的 8080 端口映射到容器内部的 80 端口。
services:
        web:
                image: timinglee/mario
                container_name: game                  # 指定容器名称
                restart always #docekr 容器自动启动
                expose:
                        - 1234 # 指定容器暴露那些端口,些端口仅对链接的服务可见,不会映射到主机的端口
                ports:
                        - "80:8080"
4. 环境变量( environment
  • 为容器设置环境变量,可以在容器内部的应用程序中使用。例如, VAR1: value1 设置环境变量 VAR1 的值为 value1
services:
        web:
                images:mysql:5.7
                environment:
                        MYSQL_ROOT_PASSWORD: lee
5. 存储卷( volumes
  • 将主机上的目录或文件挂载到容器中,以实现数据持久化或共享。例如, - /host/data:/container/data 将主机上的 /host/data 目录挂载到容器内的 /container/data 路径。
services:
        test:
                image: busybox
                command: ["/bin/sh","-c","sleep 3000"]
                restart: always
                container_name: busybox1
                volumes:
                        - /etc/passwd:/tmp/passwd:ro #只读挂在本地文件到指定位置
6. 网络( networks
  • 将服务连接到特定的网络,以便不同服务的容器可以相互通信
services:
        web:
                image: nginx
                container_name: webserver
                network_mode: bridge         #使用本机自带bridge网络
services:
        test:
                image: busybox
                container_name: webserver
                command: ["/bin/sh","-c","sleep10000000"]
                #network_mode: mynet2
                networks:
                        - mynet1
                        - mynet2
networks:
        mynet1:
                driver: bridge
        mynet2:
                driver: bridge
7. 命令( command
  • 覆盖容器启动时默认执行的命令。例如, command: python app.py 指定容器启动时运行 python app.py 命令
[root@docker test]# vim busybox.yml
services:
        web:
                image: busybox
                container_name: busybox
                #network_mode: mynet2
                command: ["/bin/sh","-c","sleep1000000"]

8.6.2 网络(networks

  • 定义 Docker Compose 应用程序中使用的网络。可以自定义网络名称和驱动程序等属性。
  • 默认情况下docker compose 在执行时会自动建立网路
services:
        test:
                image: busybox1
                command: [ "/bin/sh" , "-c" , "sleep 3000" ]
                restart : always
                network_mode: default
                container_name: busybox
        test1:
                image: busybox2
                command: [ "/bin/sh" , "-c" , "sleep 3000" ]
                restart : always
                container_name: busybox1
                networks:
                        - mynet1
        test3:
                image: busybox3
                command: [ "/bin/sh" , "-c" , "sleep 3000" ]
                restart : always
                container_name: busybox1
                networks:
                        - mynet1
networks:
        mynet1:
                driver: bridge # 使用桥接驱动,也可以使用 macvlan 用于跨主机连接
        default:
                external: true # 不建立新的网络而使用外部资源
                name: bridge # 指定外部资源网络名字
        mynet2:
                ipam:
                        driver: default
                        config:
                                - subnet: 172 .28.0.0/16
                                gateway: 172 .28.0.254

8.6.3 存储卷(volumes

  • 定义 Docker Compose 应用程序中使用的存储卷。可以自定义卷名称和存储位置等属性。
services:
        test:
                image: busybox
                command: ["/bin/sh","-c","sleep 3000"]
                restart: always
                container_name: busybox1
                volumes:
                        - data:/test #挂在data卷
                        - /etc/passwd:/tmp/passwd:ro #只读挂在本地文件到指定位置
volumes:
        data:
                name: timinglee #指定建立卷的名字

8.7 企业示例

利用容器编排完成 haproxy nginx 负载均衡架构实施
services:
        web1:
                image: nginx:latest
                container_name: web1
                restart: always
                networks:
                        - mynet1
                expose:
                        - 80
                volumes:
                        - /docker/web/html1:/usr/share/nginx/html
        
        web2:
                image: nginx:latest
                container_name: web2
                restart: always
                networks:
                        - mynet1
                expose:
                        - 80
                volumes:
                        - /docker/web/html2:/usr/share/nginx/html
        haproxy:
                image: haproxy:2.3
                container_name: haproxy
                restart: always
                networks:
                        - mynet1
                        - mynet2
                volumes:
                        - /docker/conf/haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
                ports:
                        - 80:80
networks:
        mynet1:
                driver: bridge
        mynet2:
                driver: bridge

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 米家商城主题 html 页面源码分享,可用于网页设计作业
  • IDEA快捷键总结大全
  • 建筑安全寿命你知道多少?老旧危房如何逃脱‘倒塌’宿命?
  • 在C#中使用Redis
  • 虚幻5|知识点(1)寻找查看旋转,击打敌人后朝向主角
  • MySQL笔记(大斌)
  • Python世界:文件自动化备份实践
  • 聚类算法-Kmeans聚类
  • 基础闯关4
  • CentOS7虚拟机下安装及使用Docker
  • qt5.15.2在线安装选项不见了?怎么办?
  • 【Pythonj进阶】Python中的日志记录与监控:跟踪和分析应用程序行为
  • union 的正确食用方法
  • 文件包含漏洞PHP伪协议利用方法
  • Mac 安装 jdk 8详细教程
  • MyEclipse 8.0 GA 搭建 Struts2 + Spring2 + Hibernate3 (测试)
  • tab.js分享及浏览器兼容性问题汇总
  • V4L2视频输入框架概述
  • 百度贴吧爬虫node+vue baidu_tieba_crawler
  • 干货 | 以太坊Mist负责人教你建立无服务器应用
  • 类orAPI - 收藏集 - 掘金
  • 聊聊flink的TableFactory
  • 码农张的Bug人生 - 见面之礼
  • 【运维趟坑回忆录】vpc迁移 - 吃螃蟹之路
  • 格斗健身潮牌24KiCK获近千万Pre-A轮融资,用户留存高达9个月 ...
  • ###51单片机学习(2)-----如何通过C语言运用延时函数设计LED流水灯
  • ()、[]、{}、(())、[[]]等各种括号的使用
  • (Arcgis)Python编程批量将HDF5文件转换为TIFF格式并应用地理转换和投影信息
  • (C#)获取字符编码的类
  • (HAL)STM32F103C6T8——软件模拟I2C驱动0.96寸OLED屏幕
  • (切换多语言)vantUI+vue-i18n进行国际化配置及新增没有的语言包
  • (太强大了) - Linux 性能监控、测试、优化工具
  • (一) storm的集群安装与配置
  • (转)如何上传第三方jar包至Maven私服让maven项目可以使用第三方jar包
  • .net core webapi Startup 注入ConfigurePrimaryHttpMessageHandler
  • .net wcf memory gates checking failed
  • .net 后台导出excel ,word
  • .NET 指南:抽象化实现的基类
  • .NET/C# 将一个命令行参数字符串转换为命令行参数数组 args
  • .net6 core Worker Service项目,使用Exchange Web Services (EWS) 分页获取电子邮件收件箱列表,邮件信息字段
  • .NET开发不可不知、不可不用的辅助类(一)
  • ??eclipse的安装配置问题!??
  • @angular/cli项目构建--http(2)
  • @html.ActionLink的几种参数格式
  • @RequestMapping处理请求异常
  • [ 手记 ] 关于tomcat开机启动设置问题
  • [000-01-022].第06节:RabbitMQ中的交换机介绍
  • [04]Web前端进阶—JS伪数组
  • [20190416]完善shared latch测试脚本2.txt
  • [AutoSar]工程中的cpuload陷阱(三)测试
  • [C#]使用深度学习算法opencvsharp部署RecRecNet广角图像畸变矫正校正摄像广角镜头畸变图像
  • [ERROR] ocp-server-ce-py_script_start_check-4.2.1 RuntimeError: ‘tenant_name‘
  • [HEOI2013]ALO
  • [i.MX]飞思卡尔IMX6处理器的GPIO-IOMUX_PAD说明
  • [java进阶]——方法引用改写Lambda表达式