一篇文章快速学会docker容器技术
Docker是管理容器的引擎,为应用打包、部署平台,而非单纯的虚拟化技术轻量级虚拟化:Docker 容器相较于传统的虚拟机更加轻量和高效,能够快速启动和停止,节省系统资源。例如,启动一个 Docker 容器可能只需要几秒钟,而启动一个虚拟机则可能需要几分钟。一致性:确保应用程序在不同的环境中(如开发、测试、生产)具有一致的运行表现。无论在本地还是云端,应用的运行环境都能保持相同,减少了因环境差异导
目录
5.6.1 CNM (Container Network Model)
6.4 数据卷容器(Data Volume Container
6.5 bind mount 数据卷和docker managed 数据卷的对比
一、Docker简介及部署方法
1.1Docker简介
1.1.1什么是docker
Docker是管理容器的引擎,为应用打包、部署平台,而非单纯的虚拟化技术
它具有以下几个重要特点和优势:
轻量级虚拟化
:Docker 容器相较于传统的虚拟机更加轻量和高效,能够快速启动和停止,节省系统资源。
例如,启动一个 Docker 容器可能只需要几秒钟,而启动一个虚拟机则可能需要几分钟。
一致性
:确保应用程序在不同的环境中(如开发、测试、生产)具有一致的运行表现。
无论在本地还是云端,应用的运行环境都能保持相同,减少了因环境差异导致的问题。
可移植性
:可以轻松地将 Docker 容器从一个平台迁移到另一个平台,无需担心依赖和环境配置的差异。
比如,在本地开发的容器可以无缝部署到云服务器上。
高效的资源利用:多个 Docker 容器可以共享主机的操作系统内核,从而更有效地利用系统资源。
易于部署和扩展:能够快速部署新的应用实例,并且可以根据需求轻松地进行水平扩展。
总之,Docker 极大地简化了应用程序的开发、部署和管理流程,提高了开发效率和运维的便利性。它在现代软件开发和云计算领域得到了广泛的应用。
1.1.2 docker在企业中的应用场景
在企业中docker作为业务的最小载体而被广泛应用
通过docker企业可以更效率的部署应用并更节省资源
[!NOTE]
IaaS(Infrastructure as a Service),即基础设施即服务
PaaS是(Platform as a Service)即指平台即服务
SaaS(Software as a Service)软件运营服务是
1.1.3 docker与虚拟化的对比
1.1.4 docker的优势
对于开发人员:Build once、Run anywhere。
对于运维人员:Configure once、Run anything
容器技术大大提升了IT人员的幸福指数!
二 、部署docker
2.1 容器工作方法
2.2 部署第一个容器
官方站点: https://docs.docker.com/
2.2.1 配置软件仓库
在RHEL9中做的配置
[root@docker ~]# cd /etc/yum.repos.d/
[root@docker yum.repos.d]# vim docker.repo
[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
RHEL9中做的配置
[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
#安装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中 需要
]# 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
]# sysctl --system ]
# systemctl restart docker、
二 Docker的基本操作
2.1 Docker镜像管理
2.1.1 搜索镜像
[root@Docker-node1 ~]# docker search nginx
NAME DESCRIPTION STARS OFFICIAL
nginx Official build of Nginx. 20094 [OK]
@@@省略内容
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
运行game2048: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
注:
-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
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 #把本机文件复制到容器中
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
三、docker镜像构建
3.1 docker镜像结构
共享宿主机的kernel
base镜像提供的是最小的Linux发行版
同一docker主机支持运行多种Linux发行版
采用分层结构的最大好处是:共享资源
3.2 镜像运行的基本原理
- Copy-on-Write 可写容器层
- 容器层以下所有镜像层都是只读的
- docker从上往下依次查找文件
- 容器层保存镜像变化的部分,并不会对镜像本身进行任何修改
- 一个镜像最多127层
3.3 镜像获得方式
- 基本镜像通常由软件官方提供
- 企业镜像可以用官方镜像+Dockerfile来生成
- 系统关于镜像的获取动作有两种:
- docker pull 镜像地址
- docker load –i 本地镜像包
3.4 镜像构建
3.4.1 构建参数
参数示例及用法
#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.0s2 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@server1 docker]# vim Dockerfile
FROM centos:7 AS build
ADD nginx-1.23.3.tar.gz /mnt
WORKDIR /mnt/nginx-1.23.3
RUN yum install -y gcc make pcre-devel openssl-devel && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && ./configure --with-http_ssl_module --with-http_stub_status_module && make && make install && cd .. && rm -fr nginx-1.23.3 && yum clean all
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"][root@server1 docker]# docker build -t webserver:v2 .
[root@server1 docker]# docker images webserver
REPOSITORY TAG IMAGE ID CREATED SIZE
webserver v2 caf0f80f2332 4 seconds ago 317MB
webserver v1 bfd6774cc216 About an hour ago 494MB
方法2.多阶段构建
[root@server1 docker]# vim Dockerfile
FROM centos:7 AS build
ADD nginx-1.23.3.tar.gz /mnt
WORKDIR /mnt/nginx-1.23.3
RUN yum install -y gcc make pcre-devel openssl-devel && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && ./configure --with-http_ssl_module --with-http_stub_status_module && make && make install && cd .. && rm -fr nginx-1.23.3 && yum clean allFROM centos:7
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;"][root@server1 docker]# docker build -t webserver:v3 .
[root@server1 docker]# docker images webserver
REPOSITORY TAG IMAGE ID CREATED SIZE
webserver v3 1ac964f2cefe 29 seconds ago 205MB
webserver v2 caf0f80f2332 3 minutes ago 317MB
webserver v1 bfd6774cc216 About an hour ago 494MB
方法 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/localtimeFROM 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 292MBnginx 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
Docker Hub 是 Docker 官方提供的一个公共的镜像仓库服务。
它是 Docker 生态系统中最知名和广泛使用的镜像仓库之一,拥有大量的官方和社区贡献的镜像。
以下是 Docker Hub 的一些关键特点和优势:
1. 丰富的镜像资源:涵盖了各种常见的操作系统、编程语言运行时、数据库、 Web 服务器等众多应用的镜像。
例如,您可以轻松找到 Ubuntu、CentOS 等操作系统的镜像,以及 MySQL、Redis 等数据库的镜像。
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-storesLogin 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.ymlhostname: 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 --helpNote: 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 管理仓库
登陆
建立仓库项目
上传镜像
注意:
[root@localhost harbor]# cat /etc/docker/daemon.json
{
"insecure-registries":["reg.timinglee.org"] #这个是必须加的,要不然会登陆不进去
}
[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-storesLogin 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 0eth0: 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 0lo: 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 0vethaa7cd55: 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 0docker0: 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 LOCALChain INPUT (policy ACCEPT)
target prot opt source destinationChain OUTPUT (policy ACCEPT)
target prot opt source destination
DOCKER all -- 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCALChain 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 LOCALChain INPUT (policy ACCEPT)
target prot opt source destinationChain OUTPUT (policy ACCEPT)
target prot opt source destination
DOCKER all -- 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCALChain 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:80Chain 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跨主机网络
在生产环境中,我们的容器不可能都在同一个系统中,所以需要容器具备跨主机通信的能力
跨主机网络解决方案
docker原生的overlay和macvlan
第三方的flannel、weave、calico
众多网络方案是如何与docker集成在一起的
libnetwork docker容器网络库
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
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 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 mount | docker 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 下面有很多诸如 cpuset、cpu、 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 bytesDevice 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 bytesDisk /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 bytesDisk /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 常用命令
一、服务管理
. 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: busybox1test2:
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 usr2. 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
更多推荐
所有评论(0)