目录
5.6.1 CNM (Container Network Model)
6.4 数据卷容器(Data Volume Container)
6.5 bind mount 数据卷和docker managed 数据卷的对比
1. 服务名称(service1_name/service2_name 等):
一 Docker简介及部署方法
1.1 Docker简介
Docker之父Solomon Hykes:Docker就好比传统的货运集装箱
2008 年LXC(LinuX Contiainer)发布,但是没有行业标准,兼容性非常差
docker2013年首次发布,由Docker, Inc开发
1.1.1 什么是docker?
·Docker是管理容器的引擎,为应用打包、部署平台,而非单纯的虚拟化技术
它具有以下几个重要特点和优势:
1. 轻量级虚拟化
:Docker 容器相较于传统的虚拟机更加轻量和高效,能够快速启动和停止,节省系统资源。
例如,启动一个 Docker 容器可能只需要几秒钟,而启动一个虚拟机则可能需要几分钟。
2. 一致性
:确保应用程序在不同的环境中(如开发、测试、生产)具有一致的运行表现。
无论在本地还是云端,应用的运行环境都能保持相同,减少了因环境差异导致的问题。
3. 可移植性
:可以轻松地将 Docker 容器从一个平台迁移到另一个平台,无需担心依赖和环境配置的差
异。
比如,在本地开发的容器可以无缝部署到云服务器上。
4. 高效的资源利用:多个 Docker 容器可以共享主机的操作系统内核,从而更有效地利用系统资
源。
5. 易于部署和扩展:能够快速部署新的应用实例,并且可以根据需求轻松地进行水平扩展。
水平扩展:加主机,加集群
总之,Docker 极大地简化了应用程序的开发、部署和管理流程,提高了开发效率和运维的便利性。
它在现代软件开发和云计算领域得到了广泛的应用。
1.1.2 docker在企业中的应用场景
在企业中docker作为业务的最小载体而被广泛应用
通过docker企业可以更效率的部署应用并更节省资源
IaaS(Infrastructure as a Service),即基础设施即服务
PaaS是(Platform as a Service)即指平台即服务
SaaS(Software as a Service)软件运营服务是
1.1.3 docker与虚拟化的对比
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 配置软件仓库
[root@docker-node1 ~]# cd /etc/yum.repos.d/
[root@docker-node1 yum.repos.d]# vim docker.repo
[docker]
name=docker-ce
baseurl=https://mirrors.tuna.tsinghua.edu.cn/dockerce/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
2.2.2 安装docker-ce并启动服务
[root@docker-node1 yum.repos.d]# yum install -y docker-ce
#编辑docker启动文件,设定其使用iptables的网络设定方式,默认使用nftables
[root@docker-node1 yum.repos.d]# vim /usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
--iptables=true
[root@docker-node1 ~]# systemctl enable --now docker
Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /usr/lib/systemd/system/docker.service.
[root@docker-node1 ~]# docker info
2.2.3 激活内核网络选项
#在rhel7中 需要
[root@Docker-node1 ~]# vim /etc/sysctl.d/docker.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
[root@Docker-node1 ~]# sysctl --system
[root@Docker-node1 ~]# systemctl restart docker
使用软件包安装docker
[root@harbor ~]# tar xvf docker.tar.gz
[root@harbor ~]# yum install *.rpm -y
[root@harbor ~]# systemctl start docker
#导入几个镜像
[root@harbor ~]# docker load -i game2048.tar.gz
[root@harbor ~]# docker load -i mario.tar.gz
[root@harbor ~]# docker load -i nginx-latest.tar.gz
[root@harbor ~]# docker load -i busybox-latest.tar.gz
#查看镜像
[root@harbor ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 5ef79149e0ec 13 days ago 188MB
busybox latest 65ad0d468eb1 15 months ago 4.26MB
timinglee/game2048 latest 19299002fdbe 7 years ago 55.5MB
timinglee/mario latest 9a35a9e43e8c 8 years ago 198MB
二 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-node1 ~]# docker pull busybox
[root@Docker-node1 ~]# docker pull nginx:latest
#查看本地镜像
[root@Docker-node1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 5ef79149e0ec 12 days ago 188MB
busybox latest 65ad0d468eb1 15 months ago 4.26MB
timinglee/game2048 latest 19299002fdbe 7 years ago 55.5MB
timinglee/mario latest 9a35a9e43e8c 8 years ago 198MB
alpine 版本:nginx镜像的最小安装发型版本
2.1.3 查看镜像信息
[root@Docker-node1 ~]# docker image inspect nginx:latest
2.1.4 导出镜像
#保存镜像
[root@Docker-node1 ~]# docker image save nginx:latest -o nginx-latest.tar.gz
[root@Docker-node1 ~]# docker image save nginx:latest nginx:latest-alpine -o nginx.tag.gz
#保存所有镜像
[root@Docker-node1 ~]# docker save `docker images | awk 'NR>1{print $1":"$2}'` -o images.tar.gz
·-o:指定导出镜像的位置;
·可以同时导出多个镜像到一个文件中;
·指定.tar.gz 可以导出并压缩。
如果要导入镜像的方法:
[root@Docker-node1 ~]# docker load -i nginx-latest.tar.gz
2.1.5 删除镜像
[root@Docker-node1 ~]# docker rmi nginx:latest
#删除所有的镜像
[root@Docker-node1 ~]# docker rmi `docker images | awk 'NR>1{print $1":"$2}'`
2.2 容器的常用操作
2.2.1 启动容器
#-d #后台运行
[root@Docker-node1 ~]# docker run -d --name mario -p 80:8080 timinglee/mario
8c1484ac20b086df80162e22c361bc32d02858d50860b3277d07f468e974ba56
#需要用centos7
[root@Docker-node1 ~]# docker run -it --name centos7 centos:7
[root@ea2fba709637 /]#
[root@ea2fba709637 /]# #进入到容器中,按<ctrl>+<d>退出并停止容器,#按<ctrl>+<pq>退出但不停止容器
#重新进入容器
[root@Docker-node1 ~]# docker attach centos7
[root@ea2fba709637 /]#
#在容器中执行命令
[root@docker ~]# docker exec -it test 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)
-d #后台运行
-i #交互式运行
-t #打开一个终端
--name #指定容器名称
-p #端口映射 -p 80:8080 把容器8080端口映射到本机80端口
--rm #容器停止自动删除容器
--network #指定容器使用的网络
2.2.2 查看容器运行信息
[root@Docker-node1 ~]# docker ps #查看当前运行容器
[root@Docker-node1 ~]# docker ps -a #查看所有容器
[root@Docker-node1 ~]# docker inspect busybox #查看容器运行的详细信息
2.2.3 停止和运行容器
[root@Docker-node1 ~]# docker stop busybox #停止容器
[root@Docker-node1 ~]# docker kill busybox #杀死容器,可以使用信号
[root@Docker-node1 ~]# docker start busybox #开启停止的容器
容器内的第一个进程必须一直处于运行的状态,否则这个容器,就会处于退出状态!
2.2.4 删除容器
[root@Docker-node1 ~]# docker rm centos7 #删除停止的容器
[root@Docker-node1 ~]# docker rm -f busybox #删除运行的容器
[root@Docker-node1 ~]# docker container prune -f #删除所有停止的容器
2.2.5 容器内容提交
默认情况下,容器被删除后,在容器中的所有操作都会被清理,包括要保存的文件
如果想永久保存,那么我们需要把动作提交,提交后会生成新的镜像
当我们在运行新镜像后即可看到我们提交的内容
[root@Docker-node1 ~]# docker run -it --name test busybox
/ # ls
bin dev etc home lib lib64 proc root sys tmp usr var
/ # touch hahaha
/ # ls
bin etc home lib64 root tmp var
dev hahaha lib proc sys usr
/ #
[root@Docker-node1 ~]# docker rm test #删掉容器后
test
[root@Docker-node1 ~]# docker run -it --name test busybox #删掉容器后开启新的容器文件不存在
/ # ls
bin dev etc home lib lib64 proc root sys tmp usr var
/ #
#提交
[root@Docker-node1 ~]# docker commit -m "add leefile" test busybox:v1 #类似于生成一个新的镜像
sha256:a43d3f2c0e23f01c4685c986b87282be0309d28ed28975b01f5f8b303b803ef5
[root@Docker-node1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
busybox v1 a43d3f2c0e23 16 seconds ago 4.26MB
....
[root@Docker-node1 ~]# docker image history busybox:v1
IMAGE CREATED CREATED BY SIZE COMMENT
a43d3f2c0e23 6 minutes ago sh 8B add leefile
65ad0d468eb1 15 months ago BusyBox 1.36.1 (glibc), Debian 12 4.26MB
此方法不利于企业审计,所以不推荐使用,在企业中我们多用Dockerfile来构建镜像
2.2.6 系统中的文件和容器中的文件传输
#把容器中的文件复制到本机,确保容器打开
[root@Docker-node1 ~]# docker cp test:/hahafile /mnt
Successfully copied 1.54kB to /mnt
[root@Docker-node1 ~]# ll /mnt
总用量 0
-rw-r--r-- 1 root root 0 8月 27 22:51 hahafile
drwxr-xr-x. 2 root root 6 7月 30 23:02 hgfs
[root@Docker-node1 ~]# docker cp test2:/leefile /mnt #把容器中的文件复制到本机
Successfully copied 1.54kB to /mnt
[root@Docker-node1 ~]# docker cp /etc/fstab test2:/fstab #把本机文件复制到容器中
2.2.7 查询容器内部日志
[root@Docker-node1 ~]# docker logs web
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to
perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-bydefault.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of
/etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in
/etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2024/08/14 07:50:01 [notice] 1#1: using the "epoll" event method
2024/08/14 07:50:01 [notice] 1#1: nginx/1.27.0
2024/08/14 07:50:01 [notice] 1#1: built by gcc 12.2.0 (Debian 12.2.0-14)
2024/08/14 07:50:01 [notice] 1#1: OS: Linux 5.14.0-427.13.1.el9_4.x86_64
2024/08/14 07:50:01 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1073741816:1073741816
2024/08/14 07:50:01 [notice] 1#1: start worker processes
2024/08/14 07:50:01 [notice] 1#1: start worker process 29
2024/08/14 07:50:01 [notice] 1#1: start worker process 30
172.17.0.1 - - [14/Aug/2024:07:50:20 +0000] "GET / HTTP/1.1" 200 615 "-"
"curl/7.76.1" "-"
三 docker镜像构建
3.1 docker镜像结构
·共享宿主机的kernel
·base镜像提供的是最小的Linux发行版
·同一docker主机支持运行多种Linux发行版
·采用分层结构的最大好处是:共享资源
构建镜像
[root@Docker-node1 ~]# mkdir docker/
[root@Docker-node1 ~]# cd docker/
[root@Docker-node1 docker]# touch hahafile
[root@Docker-node1 docker]# vim Dockerfile
FROM busybox
RUN touch hahafile
#开始构建
[root@Docker-node1 docker]# docker build -t busybox:v2 .
[+] Building 0.4s (6/6) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 529B 0.0s
=> [internal] load metadata for docker.io/library/busybox:latest 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> CACHED [1/2] FROM docker.io/library/busybox:latest 0.0s
=> [2/2] RUN touch hahafile 0.3s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:f913f8384760b6308808adb1d7f391665d6c42b99efc0f6c577d33 0.0s
=> => naming to docker.io/library/busybox:v2 0.0s
[root@Docker-node1 docker]#
通过指定文件构建
[root@Docker-node1 docker]# mv Dockerfile haha
[root@Docker-node1 docker]# docker build -f /root/docker/haha -t busybox:v3 .
[+] Building 0.0s (6/6) FINISHED docker:default
=> [internal] load build definition from haha 0.0s
=> => transferring dockerfile: 523B 0.0s
=> [internal] load metadata for docker.io/library/busybox:latest 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/2] FROM docker.io/library/busybox:latest 0.0s
=> CACHED [2/2] RUN touch hahafile 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:f913f8384760b6308808adb1d7f391665d6c42b99efc0f6c577d33 0.0s
=> => naming to docker.io/library/busybox:v3 0.0s
[root@Docker-node1 docker]#
3.2 镜像运行的基本原理
·Copy-on-Write 可写容器层
·容器层以下所有镜像层都是只读的
·docker从上往下依次查找文件
·容器层保存镜像变化的部分,并不会对镜像本身进行任何修改
·一个镜像最多127层
3.3 镜像获得方式
·基本镜像通常由软件官方提供
·企业镜像可以用官方镜像+Dockerfile来生成
·系统关于镜像的获取动作有两种:
docker pull 镜像地址
docker load –i 本地镜像包
3.4 镜像构建
3.4.1 构建参数
#FROM COPY 和LABEL
FROM 指定base镜像
COPY 复制文件
LABEL 指定作者信息
#FROM COPY 和MAINTAINER
[root@Docker-node1 ~]# mkdir docker/
[root@Docker-node1 ~]# cd docker/
[root@Docker-node1 docker]# touch hahafile
[root@Docker-node1 docker]# vim Dockerfile
FROM busybox:latest #指定使用的基础镜像
LABEL Mail="zhang@zhang.org" #指定作者信息
COPY hahafile / #复制当前目录文件到容器指定位置,leefile必须在当前目录中
#构建镜像
[root@Docker-node1 docker]# docker build -t busybox:v1 .
#进入查看
[root@Docker-node1 docker]# docker run -it --rm --name test busybox:v1
/ # ls
bin etc home lib64 root tmp var
dev hahafile lib proc sys usr
/ #
#查看构建
[root@Docker-node1 docker]# docker history busybox:v1
IMAGE CREATED CREATED BY SIZE COMMENT
c17159161486 12 minutes ago COPY hahafile / # buildkit 0B buildkit.doc
<missing> 12 minutes ago LABEL Mail=zhang@zhang.org 0B buildkit.doc
<missing> 15 months ago BusyBox 1.36.1 (glibc), Debian 12 4.26MB
#ADD 指定压缩文件
[root@Docker-node1 docker]# touch hahafile{1..3}
[root@Docker-node1 docker]# tar zcf hahafile.gz hahafile*
[root@Docker-node1 docker]# vim Dockerfile
FROM busybox:latest
LABEL Mail="zhang@zhang.org"
COPY hahafile /
ADD hahafile.gz /
[root@Docker-node1 docker]# docker build -t busybox:v1 .
#进入查看
[root@Docker-node1 docker]# docker run -it --rm --name test busybox:v1
/ # ls
bin etc hahafile1 hahafile3 lib proc sys usr
dev hahafile hahafile2 home lib64 root tmp var
/ #
#ENV CMD
ENV 指定环境变量
CMD 在启动容器时自动运行动作可以被覆盖
#cmd 有三种写法
#第一种
[root@Docker-node1 docker]# vim Dockerfile
FROM busybox:latest
LABEL Mail="zhang@zhang.org"
COPY hahafile /
ADD hahafile.gz /
ENV NAME=lee
CMD echo $NAME
#CMD ["/bin/echo", "$NAME"]
#CMD ["/bin/sh", "-c", "/bin/echo $NAME"]
[root@Docker-node1 docker]# docker build -t busybox:v1 .
[root@Docker-node1 docker]# docker run -it --rm --name test busybox:v1
lee
#第二种
[root@Docker-node1 docker]# vim Dockerfile
FROM busybox:latest
LABEL Mail="zhang@zhang.org"
COPY hahafile /
ADD hahafile.gz /
ENV NAME=lee
#CMD echo $NAME
CMD ["/bin/echo", "$NAME"]
#CMD ["/bin/sh", "-c", "/bin/echo $NAME"]
[root@Docker-node1 docker]# docker build -t busybox:v1 .
[root@Docker-node1 docker]# docker run -it --rm --name test busybox:v1
$NAME
#第三种
[root@Docker-node1 docker]# vim Dockerfile
FROM busybox:latest
LABEL Mail="zhang@zhang.org"
COPY hahafile /
ADD hahafile.gz /
ENV NAME=lee
#CMD echo $NAME
#CMD ["/bin/echo", "$NAME"]
CMD ["/bin/sh", "-c", "/bin/echo $NAME"]
[root@Docker-node1 docker]# docker build -t busybox:v1 .
[root@Docker-node1 docker]# docker run -it --rm --name test busybox:v1
lee
#如果用sh
[root@Docker-node1 docker]# docker run -it --rm --name test busybox:v1 sh
/ #
cmd的问题:后面写sh命令cmd会被会被替代无法执行
#ENTRYPOINT
ENTRYPOINT 和CMD功能和用法类似,但动作不可被覆盖
[root@Docker-node1 docker]# vim Dockerfile
FROM busybox:latest
LABEL Mail="zhang@zhang.org"
COPY hahafile /
ADD hahafile.gz /
ENV NAME=lee
#CMD echo $NAME
#CMD ["/bin/echo", "$NAME"]
#CMD ["/bin/sh", "-c", "/bin/echo $NAME"]
ENTRYPOINT echo $NAME
[root@Docker-node1 docker]# docker build -t busybox:v1 .
[root@Docker-node1 docker]# docker run -it --rm --name test busybox:v1 sh
lee
#EXPOSE VOLUME WORKDIR
EXPOSE 暴漏容器端口
VOLUME 申明数据卷,通常指数据挂载点
WORKDIR 切换路径
[root@Docker-node1 docker]# vim Dockerfile
FROM busybox:latest
LABEL Mail="zhang@zhang.org"
COPY hahafile /
ENV NAME=zhang
EXPOSE 80 443
VOLUME /mnt
WORKDIR /mnt
RUN touch hahafile
[root@Docker-node1 docker]# docker build -t busybox:v1 .
[root@Docker-node1 docker]# docker run -it --rm --name test busybox:v1
/mnt # ls
hahafile
#如果想看挂载目录
#查看
[root@Docker-node1 mnt]# docker inspect test
#找到"Source": "/var/lib/docker/volumes/31a36f0e268ee8607ca41a121639e0e78d5f7e88fe44a0b8dc239adaeecce17b/_data",
#然后主机cd到目录
[root@Docker-node1 ~]# cd /var/lib/docker/volumes/31a36f0e268ee8607ca41a121639e0e78d5f7e88fe44a0b8dc239adaeecce17b/_data
[root@Docker-node1 _data]# ls
hahafile
本地挂载路径的
3.4.2 Dockerfile实例
由于是用的红帽9,7版本有的无法适应
解决方法:
添加一个7的镜像,做网络仓库
[root@Docker-node1 docker]# yum install httpd -y
#修改端口
[root@Docker-node1 docker]# vim /etc/httpd/conf/httpd.conf
Listen 8888
[root@Docker-node1 docker]# systemctl start httpd
[root@Docker-node1 docker]# mkdir /var/www/html/rhel7.9
[root@Docker-node1 docker]# mount /dev/sr1 /var/www/html/rhel7.9
mount: /var/www/html/rhel7.9: WARNING: source write-protected, mounted read-only.
#浏览器访问
[root@Docker-node1 docker]# docker run -it --name centos centos:7
[root@14901f234ac9 /]# cd /etc/yum.repos.d/
[root@14901f234ac9 yum.repos.d]# ls
CentOS-Base.repo CentOS-Debuginfo.repo CentOS-Sources.repo CentOS-fasttrack.repo
CentOS-CR.repo CentOS-Media.repo CentOS-Vault.repo CentOS-x86_64-kernel.repo
[root@14901f234ac9 yum.repos.d]# rm -rf *
#注意:想要看IP是多少,换一个终端
#[root@Docker-node1 ~]# docker inspect centos
#找到下面的
# "Gateway": "172.17.0.1",
# "IPAddress": "172.17.0.3",
#所以写172.17.0.1
[root@14901f234ac9 yum.repos.d]# vi centos7.repo
[centos7]
name=centos7
baseurl=http://172.17.0.1:8888/rhel7.9
gpgcheck=0
#
[root@Docker-node1 ~]# docker commit -m "add repo" centos centos:repo
sha256:2a9678e28d52009c78da30e5992225df3793de4f9346cb5e9f8bae424e137f5d
[root@Docker-node1 docker]# docker rm centos
centos
开始生成镜像
[root@Docker-node1 docker]# docker build -t nginx:v1 .
FROM centos:repo
LABEL Mail=zhang@zhang.org
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;"]
#查看
[root@Docker-node1 docker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx v1 b51e766cf15f 2 minutes ago 356MB
3.5 镜像优化方案
3.5.1 镜像优化策略
·选择最精简的基础镜像
·减少镜像的层数
·清理镜像构建的中间产物
·选择最精简的基础镜像
·减少镜像的层数
·清理镜像构建的中间产物
3.5.2 镜像优化示例
方法1.缩减镜像层
[root@Docker-node1 docker]# vim 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 && ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_stub_status_module && make && make install && rm -rf /mnt/nginx-1.26.1 && yum clean all
EXPOSE 80 443
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]
[root@Docker-node1 docker]# docker build -t nginx:v2 .
#查看
[root@Docker-node1 docker]# docker images nginx
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx v2 0532667d9185 About a minute ago 292MB
nginx v1 b51e766cf15f 10 minutes ago 356MB
nginx latest 5ef79149e0ec 12 days ago 188MB
方法2.多阶段构建
[root@Docker-node1 docker]# vim Dockerfile
FROM centos:repo AS build
ADD nginx-1.26.1.tar.gz /mnt
WORKDIR /mnt/nginx-1.26.1
RUN yum install -y gcc make pcre-devel openssl-devel && ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_stub_status_module && make && make install && rm -rf /mnt/nginx-1.26.1 && yum clean all
FROM centos:repo
COPY --from=build /usr/local/nginx /usr/local/nginx
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]
[root@Docker-node1 docker]# docker build -t nginx:v3 .
[root@Docker-node1 docker]# docker images nginx
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx v3 8b8a3aaf3a41 15 seconds ago 210MB
nginx v2 0532667d9185 3 minutes ago 292MB
nginx v1 b51e766cf15f 12 minutes ago 356MB
nginx latest 5ef79149e0ec 12 days ago 188MB
方法3.使用最精简镜像
使用google提供的最精简镜像
下载地址:
https://github.com/GoogleContainerTools/distroless
下载镜像:
docker pull gcr.io/distroless/base
利用最精简镜像构建
[root@Docker-node1 docker]# docker load -i nginx-1.23.tar.gz
[root@Docker-node1 docker]# docker load -i debian11.tar.gz
[root@Docker-node1 docker]# vim Dockerfile
FROM nginx:1.23 AS base
ARG TIME_ZONE
RUN mkdir -p /opt/var/cache/nginx && \
cp -a --parents /usr/lib/nginx /opt && \
cp -a --parents /usr/share/nginx /opt && \
cp -a --parents /var/log/nginx /opt && \
cp -aL --parents /var/run /opt && \
cp -a --parents /etc/nginx /opt && \
cp -a --parents /etc/passwd /opt && \
cp -a --parents /etc/group /opt && \
cp -a --parents /usr/sbin/nginx /opt && \
cp -a --parents /usr/sbin/nginx-debug /opt && \
cp -a --parents /lib/x86_64-linux-gnu/ld-* /opt && \
cp -a --parents /usr/lib/x86_64-linux-gnu/libpcre* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libz.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libc* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libdl* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libpthread* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libcrypt* /opt && \
cp -a --parents /usr/lib/x86_64-linux-gnu/libssl.so.* /opt && \
cp -a --parents /usr/lib/x86_64-linux-gnu/libcrypto.so.* /opt && \
cp /usr/share/zoneinfo/${TIME_ZONE:-ROC} /opt/etc/localtime
FROM gcr.io/distroless/base-debian11
COPY --from=base /opt /
EXPOSE 80 443
ENTRYPOINT ["nginx", "-g", "daemon off;"]
[root@Docker-node1 docker]# docker images nginx
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx v4 173e6d4a23a9 39 seconds ago 34.5MB
nginx v3 8b8a3aaf3a41 3 minutes ago 210MB
nginx v2 0532667d9185 6 minutes ago 292MB
nginx v1 b51e766cf15f 15 minutes ago 356MB
nginx latest 5ef79149e0ec 12 days ago 188MB
nginx 1.23 a7be6198544f 15 months ago 142MB
四 docker 镜像仓库的管理
4.1 什么是docker仓库
Docker 仓库(Docker Registry) 是用于存储和分发 Docker 镜像的集中式存储库。
它就像是一个大型的镜像仓库,开发者可以将自己创建的 Docker 镜像推送到仓库中,也可以从仓库中拉取所需的镜像。
Docker 仓库可以分为公共仓库和私有仓库:
·公共仓库,如 Docker Hub,任何人都可以访问和使用其中的镜像。许多常用的软件和应用都有在Docker Hub 上提供的镜像,方便用户直接获取和使用。
例如,您想要部署一个 Nginx 服务器,就可以从 Docker Hub 上拉取Nginx 的镜像。
·私有仓库则是由组织或个人自己搭建和管理的,用于存储内部使用的、不希望公开的镜像。
比如,一家企业为其特定的业务应用创建了定制化的镜像,并将其存储在自己的私有仓库中,以保证安全性和控制访问权限。
通过 Docker 仓库,开发者能够方便地共享和复用镜像,加速应用的开发和部署过程。
4.2 docker hub
官网:https://hub.docker.com/
Docker Hub 是 Docker 官方提供的一个公共的镜像仓库服务。
它是 Docker 生态系统中最知名和广泛使用的镜像仓库之一,拥有大量的官方和社区贡献的镜像。
以下是 Docker Hub 的一些关键特点和优势:
1. 丰富的镜像资源:涵盖了各种常见的操作系统、编程语言运行时、数据库、Web 服务器等众多应用的镜像。
例如,您可以轻松找到 Ubuntu、CentOS 等操作系统的镜像,以及 MySQL、Redis 等数据库的镜像。
2. 官方支持:提供了由 Docker 官方维护的一些重要镜像,确保其质量和安全性。
3. 社区贡献:开发者们可以自由上传和分享他们创建的镜像,促进了知识和资源的共享。
4. 版本管理:对于每个镜像,通常都有多个版本可供选择,方便用户根据需求获取特定版本。
5. 便于搜索:用户可以通过关键词轻松搜索到所需的镜像。
4.2.1 docker hub的使用方法
#登陆官方仓库
[root@Docker-node1 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-node1 docker]# cd .docker/
[root@docker .docker]# ls
config.json
[root@Docker-node1 .docker]# cat config.json
{
"auths": {
"https://index.docker.io/v1/": {
"auth": "dGltaW5nbGVlOjY3NTE1MTVtaW5nemxu"
}
}
#gcr.io/distroless/base-debian11:latest仓库的名称,timinglee/base-debian11:latest保存的名称
[root@docker ~]# docker tag gcr.io/distroless/base-debian11:latest timinglee/base-debian11:latest
#推进仓库
[root@Docker-node1 ~]# 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
#登出
[root@Docker-node1 ~]# docker logout
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原理
index(索引),Registry(仓库)
镜像上传的步骤:
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-node1 ~]# docker pull registry
Using default tag: latest
latest: Pulling from library/registry
930bdd4d222e: Pull complete
a15309931e05: Pull complete
6263fb9c821f: Pull complete
86c1d3af3872: Pull complete
a37b1bf6a96f: Pull complete
Digest: sha256:12120425f07de11a1b899e418d4b0ea174c8d4d572d45bdb640f93bc7ca06a3d
Status: Downloaded newer image for registry:latest
docker.io/library/registry:latest
2.开启Registry
#--restart=always容器在退出时总是会被重启
[root@Docker-node1 ~]# docker run -d -p 5000:5000 --restart=always --name registry registry
12fd3e71a0658cbab05527197c3d3bb2c1f3b010180adb760c3fe53252ee3972
[root@Docker-node1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5487b6d1936b registry "/entrypoint.sh /etc…" 4 seconds ago Up 3 seconds 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp registry
3.上传镜像到仓库中
#给要上传的经镜像打标签
[root@Docker-node1 ~]# docker tag nginx:v4 172.25.254.100:5000/nginx.v4
#docker在上传的过程中默认使用https,但是我们并没有建立https认证需要的认证文件所以会报错
[root@Docker-node1 ~]# docker push 172.25.254.100:5000/nginx.v4
Using default tag: latest
The push refers to repository [172.25.254.100:5000/nginx.v4]
Get "https://172.25.254.100:5000/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
#配置非加密端口
[root@Docker-node1 ~]# vim /etc/docker/daemon.json
{
"insecure-registries" : ["http://172.25.254.100:5000"]
}
[root@Docker-node1 ~]# systemctl restart docker
#上传镜像
[root@Docker-node1 ~]# docker push 172.25.254.100:5000/nginx.v4
Using default tag: latest
The push refers to repository [172.25.254.100:5000/nginx.v4]
37f36cd04a64: Pushed
6835249f577a: Pushed
24aacbf97031: Pushed
8451c71f8c1e: Pushed
2388d21e8e2b: Pushed
c048279a7d9f: Pushed
1a73b54f556b: Pushed
2a92d6ac9e4f: Pushed
bbb6cacb8c82: Pushed
ac805962e479: Pushed
af5aa97ebe6c: Pushed
4d049f83d9cf: Pushed
9ed498e122b2: Pushed
577c8ee06f39: Pushed
5342a2647e87: Pushed
latest: digest: sha256:26f5ad9e85a80288ff0af8c9ed54232eade673d14c26d37ce98bf33dd87317ce size: 3445
#查看镜像上传
[root@Docker-node1 ~]# curl 172.25.254.100:5000/v2/_catalog
{"repositories":["nginx.v4"]}
#如何查看的位置?
#找到
#[root@Docker-node1 ~]# docker ps
#CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
#5487b6d1936b registry "/entrypoint.sh /etc…" About a minute ago Up About a minute 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp registry
#[root@Docker-node1 ~]# docker inspect registry
#在第二个长的字串的下面找到mounts,然后找到Source,在开一个终端访问路径
#[root@Docker-node1 ~]# cd /var/lib/docker/volumes/9cb1abeb2a56787c76cca05511c9c3b40b553816dfd4bf12113f26ec7349229f/_data
#[root@Docker-node1 _data]# ls
#docker
#[root@Docker-node1 _data]# cd docker/
#[root@Docker-node1 docker]# ls
#registry
#[root@Docker-node1 docker]# cd registry/
#[root@Docker-node1 registry]# ls
#v2
#[root@Docker-node1 registry]# cd v2
#[root@Docker-node1 v2]# ls
#blobs repositories
#[root@Docker-node1 v2]# cd repositories/
#[root@Docker-node1 repositories]# ls
#nginx.v4
查找本地位置:
4.3.3 为Registry提加密传输
[root@Docker-node1 ~]# mkdir certs
[root@Docker-node1 ~]# vim /etc/hosts
172.25.254.100 reg.zhang.org
#生成认证key和证书
[root@Docker-node1 ~]# openssl req -newkey rsa:4096 \
> -nodes -sha256 -keyout certs/zhang.org.key \
> -addext "subjectAltName = DNS:reg.zhang.org" \ #指定备用名称
> -x509 -days 365 -out certs/zhang.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) []:shannxi
Locality Name (eg, city) [Default City]:Xi`an
Organization Name (eg, company) [Default Company Ltd]:zhang
Organizational Unit Name (eg, section) []:docker
Common Name (eg, your name or your server's hostname) []:reg.zhang.org
Email Address []:admin@zhang.org
##启动registry仓库
[root@Docker-node1 ~]# 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/zhang.org.crt -e REGISTRY_HTTP_TLS_KEY=/certs/zhang.org.key registry
具体内容:
#启动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 \ #-v把本机的目录挂载到容器的什么地方
> -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 #key,指的是容器的地址
测试:
[root@Docker-node1 ~]# docker tag nginx:v4 reg.zhang.org/nginx:v4
#会报错,原因:docker客户端没有key和证书
[root@Docker-node1 ~]# docker push reg.zhang.org/nginx:v4
The push refers to repository [reg.zhang.org/nginx]
Get "https://reg.zhang.org/v2/": tls: failed to verify certificate: x509: certificate signed by unknown authority
#为客户端建立证书
[root@Docker-node1 ~]# mkdir /etc/docker/certs.d/reg.zhang.org/ -p
[root@Docker-node1 ~]# cp /root/certs/zhang.org.crt /etc/docker/certs.d/reg.zhang.org/ca.crt
#重启镜像
[root@Docker-node1 ~]# systemctl restart docker
#上传
[root@Docker-node1 ~]# docker push reg.zhang.org/nginx:v4
The push refers to repository [reg.zhang.org/nginx]
37f36cd04a64: Pushed
6835249f577a: Pushed
24aacbf97031: Pushed
8451c71f8c1e: Pushed
2388d21e8e2b: Pushed
c048279a7d9f: Pushed
1a73b54f556b: Pushed
2a92d6ac9e4f: Pushed
bbb6cacb8c82: Pushed
ac805962e479: Pushed
af5aa97ebe6c: Pushed
4d049f83d9cf: Pushed
9ed498e122b2: Pushed
577c8ee06f39: Pushed
5342a2647e87: Pushed
v4: digest: sha256:26f5ad9e85a80288ff0af8c9ed54232eade673d14c26d37ce98bf33dd87317ce size: 3445
#访问
[root@Docker-node1 ~]# curl -k https://reg.zhang.org/v2/_catalog
{"repositories":["nginx"]}
4.3.4 为仓库建立登陆认证
#先删除前面的镜像
[root@Docker-node1 ~]# docker rm -f registry
#安装建立认证文件的工具包
[root@Docker-node1 ~]# dnf install httpd-tools -y
#建立认证文件
[root@Docker-node1 ~]# mkdir auth
[root@Docker-node1 ~]# htpasswd -Bc auth/htpasswd zhang
New password:
Re-type new password:
Adding password for user zhang
#添加认证到registry容器中
[root@Docker-node1 ~]# 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/zhang.org.crt \
> -e REGISTRY_HTTP_TLS_KEY=/certs/zhang.org.key \
> -v /root/auth:/auth \
> -e "REGISTRY_AUTH=htpasswd" \
> -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
> -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
> registry
#一键式方法
[root@Docker-node1 ~]# docker 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/zhang.org.crt -e REGISTRY_HTTP_TLS_KEY=/certs/zhang.org.key -v /root/auth:/auth -e "REGISTRY_AUTH=htpasswd" -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd registry
[root@Docker-node1 ~]# curl -k https://reg.zhang.org/v2/_catalog -u zhang:redhat
{"repositories":["nginx"]}
#登陆测试
[root@Docker-node1 ~]# docker login reg.zhang.org
Username: zhang
Password: #redhat
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
当仓库开启认证后必须登陆仓库才能进行镜像上传
#未登陆情况下上传镜像
[root@Docker-node1 ~]# docker push reg.timinglee.org/busybox
Using default tag: latest
The push refers to repository [reg.timinglee.org/busybox]
d51af96cf93e: Preparing
no basic auth credentials
#未登陆请款下也不能下载
[root@Docker-node1 ~]# 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-node1 harbor]# docker rm -f registry
registry
[root@Docker-node1 ~]# tar zxf harbor-offline-installer-v2.5.4.tgz
[root@Docker-node1 ~]# ls
anaconda-ks.cfg certs harbor-offline-installer-v2.5.4.tgz
auth harbor
[root@Docker-node1 ~]# cd harbor/
[root@Docker-node1 harbor]# cp harbor.yml.tmpl harbor.yml
[root@Docker-node1 harbor]# vim harbor.yml
hostname: reg.zhang.org
....
certificate: /data/certs/zhang.org.crt
private_key: /data/certs/zhang.org.key
....
harbor_admin_password: redhat
[root@Docker-node1 harbor]# ./install.sh --help
Please set --with-notary #证书签名
Please set --with-trivy #安全扫描
Please set --with-chartmuseum if needs enable Chartmuseum in Harbor
#创建目录
[root@Docker-node1 ~]# mkdir /data
[root@Docker-node1 ~]# cd /data
[root@Docker-node1 data]# cp -r /root/certs/ /data/ -p
[root@Docker-node1 data]# cd
[root@Docker-node1 ~]# cd harbor/
[root@Docker-node1 harbor]# ./install.sh --with-chartmuseum
#管理harbor的容器
#关闭
[root@Docker-node1 harbor]# docker compose down
#停止
[root@Docker-node1 harbor]# docker compose stop
#启动
[root@Docker-node1 harbor]# docker compose up -d
#写windos本地解析
访问
账号:admin
密码:redhat
4.4.2 管理仓库
1.登陆
2.建立仓库项目
上传镜像
```````````````````````````````````````````````````````````````````````````````````````````````````
#登录仓库
[root@Docker-node1 ~]# docker login reg.zhang.org
Username: admin
Password: #redhat
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credential-stores
Login Succeeded
#打标签
[root@Docker-node1 ~]# docker tag busybox:latest reg.zhang.org/zhang/busybox:latest
#上传
[root@Docker-node1 ~]# docker push reg.zhang.org/zhang/busybox:latest
The push refers to repository [reg.zhang.org/zhang/busybox]
d51af96cf93e: Pushed
latest: digest: sha256:28e01ab32c9dbcbaae96cf0d5b472f22e231d9e603811857b295e61197e40a9b size: 527
[root@Docker-node1 ~]#
查看上传的镜像
设置成默认仓库
[root@Docker-node1 ~]# cd /etc/docker/
[root@Docker-node1 docker]# vim daemon.json
{
"registry-mirrors": ["https://reg.zhang.org"]
}
[root@Docker-node1 docker]# systemctl restart docker
#重启 harbor
[root@Docker-node1 docker]# cd
[root@Docker-node1 ~]# cd harbor/
[root@Docker-node1 harbor]# docker compose down
[root@Docker-node1 harbor]# docker compose up -d
#拉取镜像
[root@Docker-node1 harbor]# docker pull zhang/busybox
Using default tag: latest
latest: Pulling from zhang/busybox
Digest: sha256:28e01ab32c9dbcbaae96cf0d5b472f22e231d9e603811857b295e61197e40a9b
Status: Downloaded newer image for zhang/busybox:latest
docker.io/zhang/busybox:latest
容器的图形化界面
[root@Docker-node1 ~]# tar xfz 1panel-v1.10.13-lts-linux-amd64.tar.gz
[root@Docker-node1 ~]# cd 1panel-v1.10.13-lts-linux-amd64/
[root@Docker-node1 1panel-v1.10.13-lts-linux-amd64]# ls
1panel 1panel.service 1pctl docker install.sh LICENSE README.md
[root@Docker-node1 1panel-v1.10.13-lts-linux-amd64]# sh install.sh
██╗ ██████╗ █████╗ ███╗ ██╗███████╗██╗
███║ ██╔══██╗██╔══██╗████╗ ██║██╔════╝██║
╚██║ ██████╔╝███████║██╔██╗ ██║█████╗ ██║
██║ ██╔═══╝ ██╔══██║██║╚██╗██║██╔══╝ ██║
██║ ██║ ██║ ██║██║ ╚████║███████╗███████╗
╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝╚══════╝
[1Panel Log]: ======================= 开始安装 =======================
设置 1Panel 安装目录(默认为/opt):
[1Panel Log]: 您选择的安装路径为 /opt
[1Panel Log]: 检测到 Docker 已安装,跳过安装步骤
[1Panel Log]: 启动 Docker
设置 1Panel 端口(默认为36835):4444
[1Panel Log]: 您设置的端口为:4444
[1Panel Log]: 防火墙未开启,忽略端口开放
设置 1Panel 安全入口(默认为62a3d24b2d):
[1Panel Log]: 您设置的面板安全入口为:62a3d24b2d
设置 1Panel 面板用户(默认为c02be160fc):
[1Panel Log]: 您设置的面板用户为:c02be160fc
[1Panel Log]: 设置 1Panel 面板密码(默认为40457454b5):
[1Panel Log]: 错误:面板密码仅支持字母、数字、特殊字符(!@#$%*_,.?),长度 8-30 位
[1Panel Log]: 设置 1Panel 面板密码(默认为40457454b5): #OPENlab123
[1Panel Log]: 配置 1Panel Service
Created symlink /etc/systemd/system/multi-user.target.wants/1panel.service → /etc/systemd/system/1panel.service.
[1Panel Log]: 启动 1Panel 服务
[1Panel Log]: 1Panel 服务启动成功!
[1Panel Log]:
[1Panel Log]: =================感谢您的耐心等待,安装已经完成==================
[1Panel Log]:
[1Panel Log]: 请用浏览器访问面板:
[1Panel Log]: 外网地址: http://36.45.241.44:4444/62a3d24b2d
[1Panel Log]: 内网地址: http://172.25.254.100:4444/62a3d24b2d
[1Panel Log]: 面板用户: c02be160fc
[1Panel Log]: 面板密码: OPENlab123
[1Panel Log]:
[1Panel Log]: 项目官网: https://1panel.cn
[1Panel Log]: 项目文档: https://1panel.cn/docs
[1Panel Log]: 代码仓库: https://github.com/1Panel-dev/1Panel
[1Panel Log]:
[1Panel Log]: 如果使用的是云服务器,请至安全组开放 4444 端口
[1Panel Log]:
[1Panel Log]: 为了您的服务器安全,在您离开此界面后您将无法再看到您的密码,请务必牢记您的密码。
[1Panel Log]:
[1Panel Log]: ================================================================
[root@Docker-node1 1panel-v1.10.13-lts-linux-amd64]# 1pctl user-info
面板地址: http://$LOCAL_IP:4444/62a3d24b2d
面板用户: c02be160fc
面板密码: OPENlab123
提示:修改密码可执行命令:1pctl update password
[root@Docker-node1 1panel-v1.10.13-lts-linux-amd64]#
访问
五 Docker 网络
docker的镜像是令人称道的地方,但网络功能还是相对薄弱的部分
docker安装后会自动创建3种网络:bridge、host(主机的网络)、none
[root@docker harbor]# docker network ls
NETWORK ID NAME DRIVER SCOPE
2a93d6859680 bridge bridge local
4d81ddd9ed10 host host local
8c8c95f16b68 none null local
5.1 docker原生bridge网路
docker安装时会创建一个名为 docker0 的Linux bridge,新建的容器会自动桥接到这个接口
[root@docker mnt]# ip link show type bridge
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
mode DEFAULT group default
link/ether 02:42:5f:e2:34:6c brd ff:ff:ff:ff:ff:ff
·bridge模式下容器没有一个公有ip,只有宿主机可以直接访问,外部主机是不可见的。
·容器通过宿主机的NAT规则后可以访问外网
切换防火墙
[root@Docker-node1 ~]# grubby --update-kernel ALL --args iptables=true
[root@Docker-node1 ~]# reboot
使环境纯净
[root@Docker-node1 ~]# cd harbor/
[root@Docker-node1 harbor]# docker compose dowm
[root@Docker-node1 ~]# cd 1panel-v1.10.13-lts-linux-amd64/
[root@Docker-node1 1panel-v1.10.13-lts-linux-amd64]# 1pctl uninstall
卸载将会完全清除 1Panel 服务和数据目录,是否继续 [y/n] : y
================== 开始卸载 1Panel Linux 服务器运维管理面板 ==================
1) 停止 1Panel 服务进程...
2) 删除 1Panel 服务和数据目录...
3) 重新加载服务配置文件...
================================== 卸载完成 ==================================
[root@Docker-node1 1panel-v1.10.13-lts-linux-amd64]#
[root@Docker-node1 ~]# docker network rm 1panel-network
1panel-network
[root@Docker-node1 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
00423ad245bf bridge bridge local
209f019ce5de host host local
c4b671ab8b9d none null local
开始配置bridge
[root@Docker-node1 ~]# docker run -it --name webserver --network bridge busybox
/ # 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:14 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:1836 (1.7 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)
/ #
#再开一个终端,查看,br-64eb82a1e891:为容器使用的网卡,
[root@Docker-node1 ~]# ifconfig
br-64eb82a1e891: 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:52:67:13:03 txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 25 bytes 3846 (3.7 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
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:2ff:fefa:1323 prefixlen 64 scopeid 0x20<link>
ether 02:42:02:fa:13:23 txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 25 bytes 3846 (3.7 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.25.254.100 netmask 255.255.255.0 broadcast 172.25.254.255
inet6 fe80::a980:41de:809a:890e prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:3a:2f:c3 txqueuelen 1000 (Ethernet)
RX packets 1676 bytes 315696 (308.2 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1338 bytes 384739 (375.7 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
#查看规则
[root@Docker-node1 ~]# iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
DOCKER 0 -- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
DOCKER 0 -- 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE 0 -- 172.18.0.0/16 0.0.0.0/0
MASQUERADE 0 -- 172.17.0.0/16 0.0.0.0/0
Chain DOCKER (2 references)
target prot opt source destination
RETURN 0 -- 0.0.0.0/0 0.0.0.0/0
RETURN 0 -- 0.0.0.0/0 0.0.0.0/0
#测试网络
/ # ping www.baidu.com
PING www.baidu.com (183.2.172.42): 56 data bytes
64 bytes from 183.2.172.42: seq=0 ttl=127 time=59.028 ms
17网段的都会被
5.2 docker原生网络host
host网络模式需要在容器创建时指定 --network=host
host模式可以让容器共享宿主机网络栈,这样的好处是外部主机与容器直接通信,但是容器的网络缺少隔离性
[root@Docker-node1 ~]# docker run -it --name test --network host busybox
/ # ifconfig
br-64eb82a1e891 Link encap:Ethernet HWaddr 02:42:52:67:13:03
inet addr:172.18.0.1 Bcast:172.18.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)
docker0 Link encap:Ethernet HWaddr 02:42:02:FA:13:23
inet addr:172.17.0.1 Bcast:172.17.255.255 Mask:255.255.0.0
inet6 addr: fe80::42:2ff:fefa:1323/64 Scope:Link
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:5 errors:0 dropped:0 overruns:0 frame:0
TX packets:30 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:258 (258.0 B) TX bytes:4316 (4.2 KiB)
eth0 Link encap:Ethernet HWaddr 00:0C:29:3A:2F:C3
inet addr:172.25.254.100 Bcast:172.25.254.255 Mask:255.255.255.0
inet6 addr: fe80::a980:41de:809a:890e/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:2118 errors:0 dropped:0 overruns:0 frame:0
TX packets:1616 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:355270 (346.9 KiB) TX bytes:413165 (403.4 KiB)
eth1 Link encap:Ethernet HWaddr 00:0C:29:3A:2F:CD
UP BROADCAST RUNNING 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:1000
RX bytes:0 (0.0 B) 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:602 errors:0 dropped:0 overruns:0 frame:0
TX packets:602 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:55366 (54.0 KiB) TX bytes:55366 (54.0 KiB)
/ #
如果公用一个网络,那么所有的网络资源都是公用的,比如启动了nginx容器那么真实主机的80端口被占用,在启动第二个nginx容器就会失败
5.3 docker 原生网络none
none模式是指禁用网络功能,只有lo接口,在容器创建时使用
--network=none指定。
[root@Docker-node1 ~]# docker run -it --name none --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 (跨主机网络,针对mac地址)
bridge驱动类似默认的bridge网络模式,但增加了一些新的功能,
overlay和macvlan是用于创建跨主机网络
建议使用自定义的网络来控制哪些容器可以相互通信,还可以自动DNS解析容器名称到IP地址。
5.4.1 自定义桥接网络
自定义的桥接可以使用dns模块,而默认的没有
所以原本的 bridge的ip会变化,不变的是容器名称
但是,原生的桥接没有dns插件容器名称不能ping,自定义的可以
在建立自定义网络时,默认使用桥接模式
#创建一个自定义的网络,默认使用桥接模式
[root@Docker-node1 ~]# docker network create my_net1
64eb82a1e891f79780a6fd128767acafbc4138ff84c3a3c731c8fee29034fc0b
[root@Docker-node1 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
00423ad245bf bridge bridge local
209f019ce5de host host local
64eb82a1e891 my_net1 bridge local
c4b671ab8b9d none null local
[root@Docker-node1 ~]# docker run -it --name test --network my_net1 busybox
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:12:00:02
inet addr:172.18.0.2 Bcast:172.18.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:37 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:5454 (5.3 KiB) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
[root@Docker-node1 ~]# docker run -it --name test1 --network my_net1 busybox
/ # 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:15 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:2058 (2.0 KiB) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
/ #
#test ping test
/ # ping test1
PING test1 (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.134 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.088 ms
桥接默认是单调递增
test
test1
#关闭容器后重启容器,启动顺序调换
[root@docker ~]# docker stop test test1
test
test1
[root@docker ~]# docker start test1
test1
[root@docker ~]# docker start test
test
#我们会发容器ip颠倒
桥接也支持自定义子网和网关
[root@docker ~]# docker network create my_net2 --subnet 192.168.0.0/24 --gateway
192.168.0.100
7e77cd2e44c64ff3121a1f1e0395849453f8d524d24b915672da265615e0e4f9
[root@docker ~]# docker network inspect my_net2
[
{
"Name": "my_net2",
"Id": "7e77cd2e44c64ff3121a1f1e0395849453f8d524d24b915672da265615e0e4f9",
"Created": "2024-08-17T17:05:19.167808342+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": {}
}
]
5.4.2 为什么要自定义桥接
多容器之间如何互访?通过ip可以,但是关闭容器后重启容器,启动顺序调换,ip会调换
[root@Docker-node1 ~]# docker run -it --name test --network bridge busybox
/ # 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: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:2388 (2.3 KiB) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
[root@Docker-node1 ~]# docker run -it --name test1 --network bridge busybox
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:03
inet addr:172.17.0.3 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:13 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:1782 (1.7 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 stop test test1
test
test1
[root@docker ~]# docker start test1
test1
[root@docker ~]# docker start test
test
#我们会发容器ip颠倒
[root@Docker-node1 ~]# docker attach test
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:03
inet addr:172.17.0.3 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:15 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:2058 (2.0 KiB) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
/ #
[root@Docker-node1 ~]# docker attach test
/ #
/ #
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:03
inet addr:172.17.0.3 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:15 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:2058 (2.0 KiB) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
/ #
[root@Docker-node1 ~]# docker attach test1[root@Docker-node1 ~]# docker attach test
/ #
/ #
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:03
inet addr:172.17.0.3 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:15 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:2058 (2.0 KiB) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
/ #
/ # 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: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:2388 (2.3 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)
/ #
docker引擎在分配ip时时根据容器启动顺序分配到,谁先启动谁用,是动态变更的
多容器互访用ip很显然不是很靠谱,那么多容器访问一般使用容器的名字访问更加稳定
docker原生网络是不支持dns解析的,自定义网络中内嵌了dns
#使用默认的bridge,发现无法ping名称
[root@Docker-node1 ~]# docker rm test
test
[root@Docker-node1 ~]# docker run -it --name test --network bridge busybox
/ # 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: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:2388 (2.3 KiB) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
[root@Docker-node1 ~]# docker run -it --name test1 --network bridge busybox
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:03
inet addr:172.17.0.3 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:13 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:1782 (1.7 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)
/ #
#test ping test1
/ # ping test1
ping: bad address 'test1'
/ #
相反如果使用的是自定义的bridge
[root@Docker-node1 ~]# docker run -it --name test --network my_net1 busybox
[root@Docker-node1 ~]# docker run -it --name test1 --network my_net1 busybox
[root@Docker-node1 ~]# docker run -it --name test --network my_net1 busybox
/ # ping test1
PING test1 (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.153 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.095 ms
64 bytes from 172.18.0.3: seq=2 ttl=64 time=0.083 ms
注意:不同的自定义网络是不能通讯的
#在rhel7中使用的是iptables进行网络隔离,在rhel9中使用nftpables
[root@docker ~]# nft list ruleset可以看到网络隔离策略
5.4.3 如何让不同的自定义网络互通?
让一个容器用两个网络站
具体方法:docker network connect my_net1 test1
#添加一个自定义的bridge
[root@Docker-node1 ~]# docker network create my_net1 -d bridge
[root@Docker-node1 ~]# docker network create my_net2 -d bridge
[root@Docker-node1 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
00423ad245bf bridge bridge local
209f019ce5de host host local
64eb82a1e891 my_net1 bridge local
0f89c25aabbf my_net2 bridge local
c4b671ab8b9d none null local
[root@Docker-node1 ~]# docker run -it --name test --network my_net1 busybox
/ # 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: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:2198 (2.1 KiB) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
/ #
[root@Docker-node1 ~]# docker run -it --name test1 --network my_net2 busybox
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:15:00:02
inet addr:172.21.0.2 Bcast:172.21.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:37 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:5454 (5.3 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)
/ #
#此时test1去pingtest,发现无法ping通
/ # ping test
ping: bad address 'test'
/ #
#解决方法:
#在开一个终端,将test的网络位扔给test1
[root@Docker-node1 ~]# docker network connect my_net1 test1
#test1查看,发现test1有两个网卡
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:15:00:02
inet addr:172.21.0.2 Bcast:172.21.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:44 errors:0 dropped:0 overruns:0 frame:0
TX packets:4 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:6026 (5.8 KiB) TX bytes:212 (212.0 B)
eth1 Link encap:Ethernet HWaddr 02:42:AC:12:00:04
inet addr:172.18.0.4 Bcast:172.18.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:15 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:2058 (2.0 KiB) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:4 errors:0 dropped:0 overruns:0 frame:0
TX packets:4 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:350 (350.0 B) TX bytes:350 (350.0 B)
/ #
#此时就可以ping通
/ # ping test
PING test (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.131 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.096 ms
5.4.4 joined容器网络
让两个容器用一个网络站
Joined容器一种较为特别的网络模式,•在容器创建时使用--network=container:vm1指定。(vm1指定的是运行的容器名)
处于这个模式下的 Docker 容器会共享一个网络栈,这样两个容器之间可以使用localhost高效快速通信。
具体方法:docker run -it --name test1 --network container:test busybox
#删除容器
[root@Docker-node1 ~]# docker rm test
test
[root@Docker-node1 ~]# docker rm test1
test1
[root@Docker-node1 ~]# docker run -it --name test --network my_net1 busybox
/ # 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:14 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:1988 (1.9 KiB) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
/ #
#让第二个容器也使用这个网络位
[root@Docker-node1 ~]# docker run -it --name test1 --network container:test busybox
/ # 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: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:2268 (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)
/ #
docker run -it --name test1 --network container:test busybox
应用:
#删除容器
[root@Docker-node1 ~]# docker rm test
test
[root@Docker-node1 ~]# docker rm test1
test1
#创建一个nginx容器
[root@Docker-node1 ~]# docker run -d --name test --network my_net1 nginx
066ec825857a0b0df5267b9db873681a57f74df6b7e3fd731da0aaba5c408b18
#在另一个容器中,发现可以访问nginx
[root@Docker-node1 ~]# docker run -it --name test1 --network container:test centos:7
[root@066ec825857a /]# 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-node1 ~]# docker load -i mysql-5.7.tar.gz
[root@Docker-node1 ~]# docker load -i phpmyadmin-latest.tar.gz
[root@Docker-node1 ~]# docker run -d --name mysqladmin --network my_net1 \
> -e PMA_ARBITRARY=1 \
> -p 80:80 phpmyadmin:latest
9cd80bd6d421369f673d526e2803bd5ac08547202c2088ca7d757a7a709d62ab
[root@Docker-node1 ~]# docker run -d --name mysql --network container:mysqladmin \
> -e MYSQL_ROOT_PASSWORD='redhat' \ #mysql的密码
> mysql:5.7
a73be1e90ebdae907eed612a68db8c62d5e242cd85d27ba36f76e66ee91e7960
开启的phpmyadmin容器中是没有数据库的
这里填写的localhost:3306是因为mysql容器和phpmyadmin容器共用一个网络站
进入容器里面的mysql
[root@Docker-node1 ~]# docker exec -it mysql bash
bash-4.2# mysql -uroot -predhat
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 4
Server version: 5.7.44 MySQL Community Server (GPL)
Copyright (c) 2000, 2023, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
在浏览器中添加数据
添加前
浏览器添加
查看效果
添加表
mysql查看
插入数据
查看
5.5. 容器内外网的访问
5.5.1 容器访问外网
·在rhel7中,docker访问外网是通过iptables添加地址伪装策略来完成容器网文外网
·在rhel7之后的版本中通过nftables添加地址伪装来访问外网
[root@Docker-node1 ~]# iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
DOCKER 0 -- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
DOCKER 0 -- 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE 0 -- 172.17.0.0/16 0.0.0.0/0 #内网访问外网策略
Chain DOCKER (2 references)
target prot opt source destination
RETURN 0 -- 0.0.0.0/0 0.0.0.0/0
5.5.2 外网访问docker容器
端口映射 -p 本机端口:容器端口来暴漏端口从而达到访问效果
[root@Docker-node1 ~]# docker run -d --name webserver -p 80:80 nginx
3a9519f483e3e1ae914868d5d6d9c3af38d03a18113c5baf3ace4ebd3cbc1daa
[root@Docker-node1 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3a9519f483e3 nginx "/docker-entrypoint.…" About a minute ago Up About a minute 0.0.0.0:80->80/tcp, :::80->80/tcp webserver
[root@Docker-node1 ~]# iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
DOCKER 0 -- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
DOCKER 0 -- 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE 0 -- 172.17.0.0/16 0.0.0.0/0
MASQUERADE 6 -- 172.17.0.2 172.17.0.2 tcp dpt:80
Chain DOCKER (2 references)
target prot opt source destination
RETURN 0 -- 0.0.0.0/0 0.0.0.0/0
DNAT 6 -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 to:172.17.0.2:80
[root@Docker-node1 ~]# curl 172.25.254.100
<!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>
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是Docker项目中用于描述容器网络架构和行为的模型。Docker容器通过CNM来管理其网络连接,允许容器之间以及容器与宿主机之间进行通信。
CNM分三类组件
Sandbox:容器网络栈,包含容器接口、dns、路由表。(namespace)
Endpoint:作用是将sandbox接入network (veth pair) (类似于一个接口)
Network:包含一组endpoint,同一network的endpoint可以通信
5.6.2 macvlan网络方式实现跨主机通信
Macvlan 是一种网络技术,常用于在同一个物理网络接口上创建多个虚拟网络接口,每个虚拟接口都具有独立的 MAC 地址和 IP 地址。
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-node1 ~]# ip link set eth1 promisc on
#查看是否打开
[root@Docker-node1 ~]# ifconfig eth1
eth1: flags=4419<UP,BROADCAST,RUNNING,PROMISC,MULTICAST> mtu 1500
ether 00:0c:29:3a:2f:cd txqueuelen 1000 (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
#node2同样的配置
[root@Docker-node2 ~]# ip link set eth1 promisc on
[root@Docker-node2 ~]# ifconfig eth1
eth1: flags=4419<UP,BROADCAST,RUNNING,PROMISC,MULTICAST> mtu 1500
ether 00:0c:29:63:53:f2 txqueuelen 1000 (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
注意:eth1这款网卡在vmware中要设定为仅主机模式
2.添加macvlan网路
#添加macvlan网路
[root@Docker-node1 ~]# docker network create \
> -d macvlan \ #参数用于指定网络的驱动类型,这里指定为 macvlan,表示使用MACVLAN网络驱动。
> --subnet 4.4.4.0/24 \ #参数用于指定网络子网
> --gateway 4.4.4.4 \ #参数用于指定网络网关
> -o parent=eth1 macvlan1 #-o 参数用于传递额外的选项,这里指定 parent=eth1,表示将 macvlan1 网络挂载到 eth1 网络接口上。macvlan1是创建的网络的名字。
98ec6fd19abefd864b706553f02af4da3475ff6bfdcf1c5aeeaf13fc651a6e30
[root@Docker-node1 ~]#
#node2也做同样配置
[root@Docker-node2 ~]# docker network create -d macvlan --subnet 4.4.4.0/24 --gateway 4.4.4.4 -o parent=eth1 macvlan1
caa815db8cf23549b78de2ce7e30f4d3024e037bcf3ea16dacafdade7868b253
3.测试
[root@Docker-node1 ~]# docker run -it --rm --name test --network macvlan1 busybox
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:04:04:04:01
inet addr:4.4.4.1 Bcast:4.4.4.255 Mask:255.255.255.0
UP BROADCAST RUNNING 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)
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)
/ #
#为了看效果让node2的IP为4.4.4.2
[root@Docker-node2 ~]# docker run -it --rm --name test --network macvlan1 --ip 4.4.4.2 busybox
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:04:04:04:02
inet addr:4.4.4.2 Bcast:4.4.4.255 Mask:255.255.255.0
UP BROADCAST RUNNING 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)
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)
/ #
#node1测试
/ # ping 4.4.4.2
PING 4.4.4.2 (4.4.4.2): 56 data bytes
64 bytes from 4.4.4.2: seq=0 ttl=64 time=0.856 ms
64 bytes from 4.4.4.2: seq=1 ttl=64 time=0.278 ms
两台主机配置了两个不同的容器,容器之间可以跨主机通信
六 Docker 数据卷管理及优化
Docker 数据卷是一个可供容器使用的特殊目录,它绕过了容器的文件系统,直接将数据存储在宿主机上。
这样可以实现以下几个重要的目的:
·数据持久化:即使容器被删除或重新创建,数据卷中的数据仍然存在,不会丢失。
·数据共享:多个容器可以同时挂载同一个数据卷,实现数据的共享和交互。
·独立于容器生命周期:数据卷的生命周期独立于容器,不受容器的启动、停止和删除的影响。
6.1 为什么要用数据卷
docker分层文件系统
·性能差
·生命周期与容器相同
docker数据卷
·mount到主机中,绕开分层文件系统
·和主机磁盘性能相同,容器删除后依然保留
·仅限本地磁盘,不能随容器迁移
docker提供了两种卷:
·bind mount (本地直接挂载)
·docker managed volume (建立一个数据卷)
6.2 bind mount 数据卷
·是将主机上的目录或文件mount到容器里。
·使用直观高效,易于理解。
·使用 -v 选项指定路径,格式 :
·v选项指定的路径,如果不存在,挂载时会自动创建
示例:
#创建几个目录
[root@Docker-node1 ~]# mkdir /zhang
[root@Docker-node1 ~]# touch /zhang/zhangfile{1..5}
[root@Docker-node1 ~]# ls /zhang/
zhangfile1 zhangfile2 zhangfile3 zhangfile4 zhangfile5
#挂载目录,并启动容器
[root@Docker-node1 ~]# docker run -it --rm --name test -v /zhang:/data:rw -v /etc/passwd:/data2/passwd busybox
/ # ls
bin data data2 dev etc home lib lib64 proc root sys tmp usr var
/ # ls /data
zhangfile1 zhangfile2 zhangfile3 zhangfile4 zhangfile5
/ # vi /data2/passwd
注意:挂载的是真机的,修改的话数据会同步到真机上面
6.3 docker managed 数据卷
·bind mount必须指定host文件系统路径,限制了移植性
·docker managed volume 不需要指定mount源,docker自动为容器创建数据卷目录
·默认创建的数据卷目录都在 /var/lib/docker/volumes 中
·如果挂载时指向容器内已有的目录,原有数据会被复制到volume中
示例:
[root@Docker-node1 ~]# docker run -d --name mysql -e MYSQL_ROOT_PASSWORD='redhat' mysql:5.7
[root@Docker-node1 ~]# ls -l /var/lib/docker/volumes
总用量 52
drwx-----x 3 root root 19 8月 30 11:50 32caf8314873e6f0d0bf56dae37296482734415828925b2bb40c691ded53e453
brw------- 1 root root 253, 0 8月 30 10:47 backingFsBlockDev
-rw------- 1 root root 65536 8月 30 11:51 metadata.db
#查看直接写的挂载目录
[root@Docker-node1 ~]# ll /var/lib/docker/volumes/32caf8314873e6f0d0bf56dae37296482734415828925b2bb40c691ded53e453/_data/
总用量 188484
-rw-r----- 1 systemd-coredump input 56 8月 30 11:50 auto.cnf
-rw------- 1 systemd-coredump input 1676 8月 30 11:50 ca-key.pem
-rw-r--r-- 1 systemd-coredump input 1112 8月 30 11:50 ca.pem
-rw-r--r-- 1 systemd-coredump input 1112 8月 30 11:50 client-cert.pem
-rw------- 1 systemd-coredump input 1680 8月 30 11:50 client-key.pem
-rw-r----- 1 systemd-coredump input 1318 8月 30 11:50 ib_buffer_pool
-rw-r----- 1 systemd-coredump input 79691776 8月 30 11:50 ibdata1
-rw-r----- 1 systemd-coredump input 50331648 8月 30 11:50 ib_logfile0
-rw-r----- 1 systemd-coredump input 50331648 8月 30 11:50 ib_logfile1
-rw-r----- 1 systemd-coredump input 12582912 8月 30 11:50 ibtmp1
drwxr-x--- 2 systemd-coredump input 4096 8月 30 11:50 mysql
lrwxrwxrwx 1 systemd-coredump input 27 8月 30 11:50 mysql.sock -> /var/run/mysqld/mysqld.sock
drwxr-x--- 2 systemd-coredump input 8192 8月 30 11:50 performance_schema
-rw------- 1 systemd-coredump input 1680 8月 30 11:50 private_key.pem
-rw-r--r-- 1 systemd-coredump input 452 8月 30 11:50 public_key.pem
-rw-r--r-- 1 systemd-coredump input 1112 8月 30 11:50 server-cert.pem
-rw------- 1 systemd-coredump input 1680 8月 30 11:50 server-key.pem
drwxr-x--- 2 systemd-coredump input 8192 8月 30 11:50 sys
#当容器删除时
[root@Docker-node1 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e6b2c83ca6b1 mysql:5.7 "docker-entrypoint.s…" 4 minutes ago Up 4 minutes 3306/tcp, 33060/tcp mysql
[root@Docker-node1 ~]# docker rm -f mysql
mysql
#发现没有东西了
[root@Docker-node1 ~]# ll /var/lib/docker/volumes/32caf8314873e6f0d0bf56dae37296482734415828925b2bb40c691ded53e453/_data/
清理未使用的 Docker 数据卷
[root@docker ~]# docker volume prune
1. 在执行 docker volume prune 命令之前,请确保你确实不再需要这些数据卷中的数据,因为该操作是不可逆的,一旦删除数据将无法恢复。
2. 如果有重要的数据存储在数据卷中,建议先进行备份,或者确保数据已经被妥善保存到其他地方。
建立数据卷
[root@Docker-node1 ~]# docker volume create mysqldate
mysqldate
[root@Docker-node1 ~]# ll /var/lib/docker/volumes/mysqldate/
总用量 0
drwxr-xr-x 2 root root 6 8月 30 13:45 _data
查看卷
[root@Docker-node1 ~]# docker volume ls
DRIVER VOLUME NAME
local mysqldate
使用建立的数据卷
[root@Docker-node1 ~]# docker run -d --rm --name mysql -e MYSQL_ROOT_PASSWORD=redhat -v mysqldate:/var/lib/mysql mysql:5.7
c026216014d3c3de4f5cb8a8f85027d5671402e159b9010af79c17b2ae2be16f
[root@docker _data]# docker run -d --name web1 -p 80:80 -v leevol1:/usr/share/nginx/html nginx
e76706848323d6c329c41c4140903f8cc441458daf1459d9016bd1ed0ab3360a
root@docker _data]# cd /var/lib/docker/volumes/leevol1/_data
[root@docker _data]# ls
[root@docker _data]# echo leevol1 > index.html
[root@docker _data]# curl 172.25.254.100
leevol1
查看挂载
[root@Docker-node1 ~]# docker inspect mysql
[root@Docker-node1 ~]# ll /var/lib/docker/volumes/mysqldate/_data/
总用量 188484
-rw-r----- 1 systemd-coredump input 56 8月 30 13:49 auto.cnf
-rw------- 1 systemd-coredump input 1680 8月 30 13:49 ca-key.pem
-rw-r--r-- 1 systemd-coredump input 1112 8月 30 13:49 ca.pem
-rw-r--r-- 1 systemd-coredump input 1112 8月 30 13:49 client-cert.pem
-rw------- 1 systemd-coredump input 1676 8月 30 13:49 client-key.pem
-rw-r----- 1 systemd-coredump input 1318 8月 30 13:49 ib_buffer_pool
-rw-r----- 1 systemd-coredump input 79691776 8月 30 13:49 ibdata1
-rw-r----- 1 systemd-coredump input 50331648 8月 30 13:49 ib_logfile0
-rw-r----- 1 systemd-coredump input 50331648 8月 30 13:49 ib_logfile1
-rw-r----- 1 systemd-coredump input 12582912 8月 30 13:49 ibtmp1
drwxr-x--- 2 systemd-coredump input 4096 8月 30 13:49 mysql
lrwxrwxrwx 1 systemd-coredump input 27 8月 30 13:49 mysql.sock -> /var/run/mysqld/mysqld.sock
drwxr-x--- 2 systemd-coredump input 8192 8月 30 13:49 performance_schema
-rw------- 1 systemd-coredump input 1680 8月 30 13:49 private_key.pem
-rw-r--r-- 1 systemd-coredump input 452 8月 30 13:49 public_key.pem
-rw-r--r-- 1 systemd-coredump input 1112 8月 30 13:49 server-cert.pem
-rw------- 1 systemd-coredump input 1676 8月 30 13:49 server-key.pem
drwxr-x--- 2 systemd-coredump input 8192 8月 30 13:49 sys
停止容器
[root@Docker-node1 ~]# docker stop mysql
mysql
[root@Docker-node1 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
查看逻辑卷是否存在
[root@Docker-node1 ~]# cd /var/lib/docker/volumes/
[root@Docker-node1 volumes]# ls
backingFsBlockDev metadata.db mysqldate
[root@Docker-node1 volumes]# cd mysqldate/_data/
[root@Docker-node1 _data]# ls
auto.cnf client-key.pem ib_logfile1 private_key.pem sys
ca-key.pem ib_buffer_pool mysql public_key.pem
ca.pem ibdata1 mysql.sock server-cert.pem
client-cert.pem ib_logfile0 performance_schema server-key.pem
删除卷
[root@Docker-node1 _data]# docker volume ls
DRIVER VOLUME NAME
local mysqldate
[root@Docker-node1 _data]# docker volume rm mysqldate
mysqldate
[root@Docker-node1 _data]# docker volume ls
DRIVER VOLUME NAME
[root@Docker-node1 _data]#
[root@Docker-node1 _data]# cd /var/lib/docker/volumes/
[root@Docker-node1 volumes]# ls
backingFsBlockDev metadata.db
删除卷的话数据会消失
另一种删除数据的方法
[root@Docker-node1 volumes]# docker volume prune
注意:全删除的话也会删除数据
6.4 数据卷容器(Data Volume Container)
数据卷容器(Data Volume Container)是 Docker 中一种特殊的容器,主要用于方便地在多个容器之间
共享数据卷。
1.建立数据卷容器
[root@Docker-node1 ~]# docker run -d --name datavol \
> -v /tmp/data1:/data1:rw \
> -v /tmp/data2:/data2:ro \
> -v /etc/resolv.conf:/etc/hosts busybox
87d5420357608ec7d579a6b9d5adceb3c8f86ba81a6e2fb2d590f64ba9cdac83
[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-node1 ~]# 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
# Based on host file: '/etc/resolv.conf' (legacy)
# Overrides: []
/ # touch data1/leefile1
/ # touch /data2/leefile1
touch: /data2/leefile1: Read-only file system
/ #
6.5 bind mount 数据卷和docker managed 数据卷的对比
相同点:
两者都是 host 文件系统中的某个路径
不同点
bind的挂载会删除掉原本容器中目录的文件
[root@Docker-node1 ~]# docker run -it --rm --name test -v /zhang:/etc:ro busybox
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: error mounting "/var/lib/docker/containers/a0ccd449af8678347fb87a7d4ed21301908f941f7bb72bba4bdf943e17508161/resolv.conf" to rootfs at "/etc/resolv.conf": open /var/lib/docker/overlay2/6eb5fab559b7e0650805bd67a9e1f1d19b531f63993e621602d67da64fcb0a87/merged/etc/resolv.conf: read-only file system: unknown.
无法启动
6.6 备份与迁移数据卷
备份数据卷
[root@Docker-node1 ~]# docker run -it --name test --rm -v test:/data busybox
/ # ls
bin dev home lib64 root tmp var
data etc lib proc sys usr
/ #
另一个容器
#--volumes-from test,使test1的挂载路径和test一样,`pwd`:/backup把当前的路径挂载到/backup
[root@Docker-node1 ~]# 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
#开始备份
/ # tar zcf /backup/data.tar.gz /data/
tar: removing leading '/' from member names
#退出查看
/ # exit
[root@Docker-node1 ~]# ll data.tar.gz
-rw-r--r-- 1 root root 89 8月 31 00:52 data.tar.gz
具体解释
#建立容器并指定使用卷到要备份的容器
[root@Docker-node1 ~]# docker run --volumes-from test \
-v `pwd`:/backup busybox \ #把当前目录挂在到容器中用于和容器交互保存要备份的容器
tar zcf /backup/data1.tar.gz /data1 #备份数据到本地
数据恢复
[root@Docker-node1 ~]# docker run -it --name test1 -v `pwd`:/backup busybox /bin/sh -c "tar zxf /backup/data.tar.gz;/bin/sh"
/ # ls
backup data etc lib proc sys usr
bin dev home lib64 root tmp var
/ # cd data/
/data # ls
七 Docker 的安全优化
Docker容器的安全性,很大程度上依赖于Linux系统自身
评估Docker的安全性时,主要考虑以下几个方面:
·Linux内核的命名空间机制提供的容器隔离安全
·Linux控制组机制对容器资源的控制能力安全。
·Linux内核的能力机制所带来的操作权限安全
·Docker程序(特别是服务端)本身的抗攻击性。
·其他安全增强机制对容器安全性的影响
查看是否打开cgroup
[root@Docker-node1 ~]# mount -t cgroup2
cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime,nsdelegate,memory_recursiveprot)
[root@Docker-node1 ~]# mount -t cgroup
改为cgroup
#在rhel9中默认使用cgroup-v2 但是cgroup-v2中不利于观察docker的资源限制情况,所以推荐使用cgroup-v1
[root@Docker-node1 ~]# grubby --update-kernel=/boot/vmlinuz-$(uname -r) \
> --args="systemd.unified_cgroup_hierarchy=0 systemd.legacy_systemd_cgroup_controller"
[root@Docker-node1 ~]#
[root@Docker-node1 ~]# mount -t cgroup2
[root@Docker-node1 ~]# 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/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
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/misc type cgroup (rw,nosuid,nodev,noexec,relatime,misc)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
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/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
[root@Docker-node1 ~]#
1 命名空间隔离的安全
·当docker run启动一个容器时,Docker将在后台为容器创建一个独立的命名空间。命名空间提供了最基础也最直接的隔离。
·与虚拟机方式相比,通过Linux namespace来实现的隔离不是那么彻底。
·容器只是运行在宿主机上的一种特殊的进程,那么多个容器之间使用的就还是同一个宿主机的操作系统内核。
·在 Linux 内核中,有很多资源和对象是不能被 Namespace 化的,比如:磁盘等等
[root@Docker-node1 ~]# docker run -d --name web nginx
c6e4742d2b36f069fca9ecf319ac5174983e3195a3269af11cc08892736bb3e6
[root@Docker-node1 ~]# docker inspect web | grep Pid
"Pid": 1980,
"PidMode": "",
"PidsLimit": null,
[root@Docker-node1 ~]# cd /proc/1980/ns/ #进程的namespace
[root@Docker-node1 ns]# ls
cgroup ipc mnt net pid pid_for_children time time_for_children user uts
#资源隔离信息
[root@Docker-node1 ns]# cd /sys/fs/cgroup/memory/docker/c6e4742d2b36f069fca9ecf319ac5174983e3195a3269af11cc08892736bb3e6/
[root@Docker-node1 c6e4742d2b36f069fca9ecf319ac5174983e3195a3269af11cc08892736bb3e6]# ls
cgroup.clone_children memory.memsw.failcnt
cgroup.event_control memory.memsw.limit_in_bytes
cgroup.procs memory.memsw.max_usage_in_bytes
memory.failcnt memory.memsw.usage_in_bytes
memory.force_empty memory.move_charge_at_immigrate
memory.kmem.failcnt memory.numa_stat
memory.kmem.limit_in_bytes memory.oom_control
memory.kmem.max_usage_in_bytes memory.pressure_level
memory.kmem.slabinfo memory.soft_limit_in_bytes
memory.kmem.tcp.failcnt memory.stat
memory.kmem.tcp.limit_in_bytes memory.swappiness
memory.kmem.tcp.max_usage_in_bytes memory.usage_in_bytes
memory.kmem.tcp.usage_in_bytes memory.use_hierarchy
memory.kmem.usage_in_bytes notify_on_release
memory.limit_in_bytes tasks
memory.max_usage_in_bytes
2 控制组资源控制的安全
·当docker run启动一个容器时,Docker将在后台为容器创建一个独立的控制组策略集合。
·Linux Cgroups提供了很多有用的特性,确保各容器可以公平地分享主机的内存、CPU、磁盘IO等资源。
·确保当发生在容器内的资源压力不会影响到本地主机系统和其他容器,它在防止拒绝服务攻击 (DDoS)方面必不可少
[root@Docker-node1 ~]# docker run -it --name test busybox #内存资源默认没有隔离
/ # free -m
total used free shared buff/cache available
Mem: 737 453 62 0 222 171
Swap: 2064 86 1978
/ # exit
[root@Docker-node1 ~]# free -m
total used free shared buff/cache available
Mem: 736 549 48 0 252 187
Swap: 2063 85 1978
[root@Docker-node1 ~]#
3 内核能力机制
·能力机制(Capability)是Linux内核一个强大的特性,可以提供细粒度的权限访问控制。
·大部分情况下,容器并不需要“真正的”root权限,容器只需要少数的能力即可。
·默认情况下,Docker采用“白名单”机制,禁用“必需功能”之外的其他权限。
4 Docker服务端防护
·使用Docker容器的核心是Docker服务端,确保只有可信的用户才能访问到Docker服务。
·将容器的root用户映射到本地主机上的非root用户,减轻容器和主机之间因权限提升而引起的安全问题。
·允许Docker 服务端在非root权限下运行,利用安全可靠的子进程来代理执行需要特权权限的操作。这些子进程只允许在特定范围内进行操作
[root@Docker-node1 ~]# ls -ld /var/lib/docker/ #默认docker是用root用户控制资源的
drwx--x--- 12 root root 171 8月 30 22:12 /var/lib/docker/
总结:做隔离,用非root用户,资源限制
7.1 Docker的资源限制
Linux Cgroups 的全称是 Linux Control Group。
·是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等。
·对进程进行优先级设置、审计,以及将进程挂起和恢复等操作。
Linux Cgroups 给用户暴露出来的操作接口是文件系统
·它以文件和目录的方式组织在操作系统的 /sys/fs/cgroup 路径下。
·执行此命令查看:mount -t cgroup
[root@Docker-node1 ~]# 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/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
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/misc type cgroup (rw,nosuid,nodev,noexec,relatime,misc)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
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/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
·在 /sys/fs/cgroup 下面有很多诸如 cpuset、cpu、 memory 这样的子目录,也叫子系统。
·在每个子系统下面,为每个容器创建一个控制组(即创建一个新目录)。
·控制组下面的资源文件里填上什么值,就靠用户执行 docker run 时的参数指定。
7.1.1.限制cpu使用
使cpu占满
#导入ubuntu镜像
[root@Docker-node1 ~]# docker load -i ubuntu-latest.tar.gz
[root@Docker-node1 ~]# docker run -it --name test1 --rm ubuntu
root@5e4de8c7c104:/# dd if=/dev/zero of=/dev/null &
[1] 10
root@5e4de8c7c104:/# top
top - 14:58:58 up 46 min, 0 user, load average: 0.29, 0.11, 0.03
Tasks: 3 total, 2 running, 1 sleeping, 0 stopped, 0 zombie
%Cpu(s): 22.8 us, 75.4 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.9 hi, 0.9 si, 0.0 st
MiB Mem : 736.9 total, 126.7 free, 366.5 used, 356.9 buff/cache
MiB Swap: 2064.0 total, 1979.2 free, 84.8 used. 370.4 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
10 root 20 0 2736 1280 1280 R 99.0 0.2 0:12.38 dd
1 root 20 0 4588 3840 3328 S 0.0 0.5 0:00.01 bash
11 root 20 0 8856 5248 3200 R 0.0 0.7 0:00.00 top
1.限制cpu的使用量
[root@Docker-node1 ~]# docker run -it --rm --name test --cpu-period 100000 --cpu-quota 20000 ubuntu
root@7a392b231371:/# dd if=/dev/zero of=/dev/null & #& 表示:运行进程在后台
[1] 9
root@7a392b231371:/# top
top - 15:02:42 up 50 min, 0 user, load average: 0.06, 0.18, 0.09
Tasks: 3 total, 2 running, 1 sleeping, 0 stopped, 0 zombie
%Cpu(s): 1.6 us, 3.1 sy, 0.0 ni, 95.3 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 736.9 total, 119.3 free, 373.6 used, 357.2 buff/cache
MiB Swap: 2064.0 total, 1980.5 free, 83.5 used. 363.3 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
9 root 20 0 2736 1408 1408 R 19.7 0.2 0:03.97 dd
1 root 20 0 4588 3840 3328 S 0.0 0.5 0:00.01 bash
10 root 20 0 8856 5120 3072 R 0.0 0.7 0:00.00 top
解释:
[root@docker ~]# docker run -it --rm --name test \
--cpu-period 100000 \ #设置 CPU 周期的长度,单位为微秒(通常为100000,即 100 毫秒)
--cpu-quota 20000 ubuntu #设置容器在一个周期内可以使用的 CPU 时间,单位也是微秒。
在开一个终端
[root@Docker-node1 docker]# cd /sys/fs/cgroup/memory/docker/6d419dfcdddf039a292b785e62e6629c4e06332a3929e35421e35a5098269e07/
[root@Docker-node1 6d419dfcdddf039a292b785e62e6629c4e06332a3929e35421e35a5098269e07]# ls
cgroup.clone_children memory.memsw.failcnt
cgroup.event_control memory.memsw.limit_in_bytes
cgroup.procs memory.memsw.max_usage_in_bytes
memory.failcnt memory.memsw.usage_in_bytes
memory.force_empty memory.move_charge_at_immigrate
memory.kmem.failcnt memory.numa_stat
memory.kmem.limit_in_bytes memory.oom_control
memory.kmem.max_usage_in_bytes memory.pressure_level
memory.kmem.slabinfo memory.soft_limit_in_bytes
memory.kmem.tcp.failcnt memory.stat
memory.kmem.tcp.limit_in_bytes memory.swappiness
memory.kmem.tcp.max_usage_in_bytes memory.usage_in_bytes
memory.kmem.tcp.usage_in_bytes memory.use_hierarchy
memory.kmem.usage_in_bytes notify_on_release
memory.limit_in_bytes tasks
memory.max_usage_in_bytes
2.限制cpu的优先级
#为了查看cpu的争抢
#关闭cpu的核心,当cpu都不空闲下才会出现争抢的情况,为了实验效果我们可以关闭一个cpu核心
[root@Docker-node1 ~]# cd /sys/devices/system/cpu
[root@Docker-node1 cpu]# ls
cpu0 cpuidle isolated modalias offline possible present uevent
cpufreq hotplug kernel_max nohz_full online power smt vulnerabilities
[root@Docker-node1 cpu]# echo 0 > /sys/devices/system/cpu/cpu1/online
[root@Docker-node1 ~]# cat /proc/cpuinfo
processor : 0
vendor_id : AuthenticAMD
cpu family : 25
model : 80
model name : AMD Ryzen 7 5800H with Radeon Graphics
stepping : 0
cpu MHz : 3194.004
cache size : 512 KB
physical id : 0
siblings : 1
core id : 0
cpu cores : 1
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 16
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 syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl tsc_reliable nonstop_tsc cpuid extd_apicid tsc_known_freq pni pclmulqdq ssse3 fma cx16 sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw topoext ibpb vmmcall fsgsbase bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xgetbv1 xsaves clzero wbnoinvd arat umip pku ospke vaes vpclmulqdq rdpid overflow_recov succor fsrm
bugs : fxsave_leak sysret_ss_attrs null_seg spectre_v1 spectre_v2 spec_store_bypass srso
bogomips : 6388.00
TLB size : 2560 4K pages
clflush size : 64
cache_alignment : 64
address sizes : 45 bits physical, 48 bits virtual
power management:
#开启容器并限制资源
#设定cpu优先级,最大为1024,值越大优先级越高
[root@Docker-node1 ~]# docker run -it --rm --name test --cpu-shares 100 ubuntu
root@e0d752ac613f:/# dd if=/dev/zero of=/dev/null &
[1] 9
root@e0d752ac613f:/# top
top - 15:15:08 up 1:02, 0 user, load average: 0.68, 0.23, 0.12
Tasks: 3 total, 2 running, 1 sleeping, 0 stopped, 0 zombie
%Cpu(s): 25.0 us, 73.5 sy, 0.0 ni, 0.0 id, 0.0 wa, 1.5 hi, 0.0 si, 0.0 st
MiB Mem : 736.9 total, 86.8 free, 405.8 used, 357.3 buff/cache
MiB Swap: 2064.0 total, 1980.7 free, 83.2 used. 331.1 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
9 root 20 0 2736 1408 1408 R 99.3 0.2 0:19.88 dd
1 root 20 0 4588 3712 3200 S 0.0 0.5 0:00.01 bash
10 root 20 0 8856 5120 3072 R 0.0 0.7 0:00.00 top
#开启另外一个容器不限制cpu的优先级
[root@Docker-node1 /]# docker run -it --rm --name test1 ubuntu
root@a6d9adb0319f:/# dd if=/dev/zero of=/dev/null &
[1] 8
root@a6d9adb0319f:/# top
top - 15:16:54 up 1:04, 0 user, load average: 1.42, 0.58, 0.26
Tasks: 3 total, 2 running, 1 sleeping, 0 stopped, 0 zombie
%Cpu(s): 23.1 us, 75.4 sy, 0.0 ni, 0.0 id, 0.0 wa, 1.5 hi, 0.0 si, 0.0 st
MiB Mem : 736.9 total, 105.2 free, 407.5 used, 337.4 buff/cache
MiB Swap: 2064.0 total, 1980.7 free, 83.2 used. 329.4 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
8 root 20 0 2736 1408 1408 R 90.4 0.2 0:17.07 dd
1 root 20 0 4588 3968 3456 S 0.0 0.5 0:00.01 bash
9 root 20 0 8856 5120 3072 R 0.0 0.7 0:00.00 top
此时:限制了cpu的情况
7.1.2 限制内存使用
#安装工具
[root@Docker-node1 ~]# yum install libcgroup-0.41-19.el8.x86_64.rpm
[root@Docker-node1 ~]# yum install libcgroup-tools-0.41-19.el8.x86_64.rpm
#开启容器并限制容器使用内存大小
[root@Docker-node1 ~]# docker run -d --name test --memory 200M --memory-swap 200M nginx
9541f388a4682764acd4209534655d16043937302c22a1d2a41211240928ca87
#查看容器内存使用限制
[root@Docker-node1 ~]# cd /sys/fs/cgroup/memory/docker/9541f388a4682764acd4209534655d16043937302c22a1d2a41211240928ca87/
[root@Docker-node1 9541f388a4682764acd4209534655d16043937302c22a1d2a41211240928ca87]# ls
cgroup.clone_children memory.memsw.failcnt
cgroup.event_control memory.memsw.limit_in_bytes
cgroup.procs memory.memsw.max_usage_in_bytes
memory.failcnt memory.memsw.usage_in_bytes
memory.force_empty memory.move_charge_at_immigrate
memory.kmem.failcnt memory.numa_stat
memory.kmem.limit_in_bytes memory.oom_control
memory.kmem.max_usage_in_bytes memory.pressure_level
memory.kmem.slabinfo memory.soft_limit_in_bytes
memory.kmem.tcp.failcnt memory.stat
memory.kmem.tcp.limit_in_bytes memory.swappiness
memory.kmem.tcp.max_usage_in_bytes memory.usage_in_bytes
memory.kmem.tcp.usage_in_bytes memory.use_hierarchy
memory.kmem.usage_in_bytes notify_on_release
memory.limit_in_bytes tasks
memory.max_usage_in_bytes
[root@Docker-node1 9541f388a4682764acd4209534655d16043937302c22a1d2a41211240928ca87]# cat memory.memsw.limit_in_bytes
209715200
[root@Docker-node1 9541f388a4682764acd4209534655d16043937302c22a1d2a41211240928ca87]# cat memory.limit_in_bytes
209715200
#测试容器内存限制,在容器中我们测试内存限制效果不是很明显,可以利用工具模拟容器在内存中写入数据
#在系统中/dev/shm这个目录被挂在到内存中
[root@Docker-node1 9541f388a4682764acd4209534655d16043937302c22a1d2a41211240928ca87]# cgexec -g memory:docker/9541f388a4682764acd4209534655d16043937302c22a1d2a41211240928ca87 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=150a41211240928ca87 dd
记录了150+0 的读入
记录了150+0 的写出
157286400字节(157 MB,150 MiB)已复制,0.529094 s,297 MB/s
[root@Docker-node1 9541f388a4682764acd4209534655d16043937302c22a1d2a41211240928ca87]# cgexec -g memory:docker/9541f388a4682764acd4209534655d16043937302c22a1d2a41211240928ca87 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=180
记录了180+0 的读入
记录了180+0 的写出
188743680字节(189 MB,180 MiB)已复制,0.168843 s,1.1 GB/s
[root@Docker-node1 9541f388a4682764acd4209534655d16043937302c22a1d2a41211240928ca87]# cgexec -g memory:docker/9541f388a4682764acd4209534655d16043937302c22a1d2a41211240928ca87 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=200
已杀死
#也可以自建控制器
[root@Docker-node1 ~]# mkdir -p /sys/fs/cgroup/memory/x1/
[root@Docker-node1 ~]# ls /sys/fs/cgroup/memory/x1/
cgroup.clone_children memory.memsw.failcnt
cgroup.event_control memory.memsw.limit_in_bytes
cgroup.procs memory.memsw.max_usage_in_bytes
memory.failcnt memory.memsw.usage_in_bytes
memory.force_empty memory.move_charge_at_immigrate
memory.kmem.failcnt memory.numa_stat
memory.kmem.limit_in_bytes memory.oom_control
memory.kmem.max_usage_in_bytes memory.pressure_level
memory.kmem.slabinfo memory.soft_limit_in_bytes
memory.kmem.tcp.failcnt memory.stat
memory.kmem.tcp.limit_in_bytes memory.swappiness
memory.kmem.tcp.max_usage_in_bytes memory.usage_in_bytes
memory.kmem.tcp.usage_in_bytes memory.use_hierarchy
memory.kmem.usage_in_bytes notify_on_release
memory.limit_in_bytes tasks
memory.max_usage_in_bytes
[root@Docker-node1 ~]# echo 209715200 > /sys/fs/cgroup/memory/x1/memory.limit_in_bytes
[root@Docker-node1 ~]# cat /sys/fs/cgroup/memory/x1/tasks #此控制器被那个进程调用
[root@Docker-node1 ~]# cgexec -g memory:x1 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=100
记录了100+0 的读入
记录了100+0 的写出
104857600字节(105 MB,100 MiB)已复制,0.0482829 s,2.2 GB/s
[root@Docker-node1 ~]# free -m
total used free shared buff/cache available
Mem: 1743 707 604 105 701 1035
Swap: 2063 0 2063
[root@Docker-node1 ~]# cgexec -g memory:x1 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=200
记录了200+0 的读入
记录了200+0 的写出
209715200字节(210 MB,200 MiB)已复制,0.0960887 s,2.2 GB/s
[root@Docker-node1 ~]# free -m
total used free shared buff/cache available
Mem: 1743 798 513 203 799 944
Swap: 2063 2 2061 #内存溢出部分被写入swap交换分区
[root@Docker-node1 ~]# cgexec -g memory:x1 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=300
记录了300+0 的读入
记录了300+0 的写出
314572800字节(315 MB,300 MiB)已复制,0.235924 s,1.3 GB/s
[root@Docker-node1 ~]# free -m
total used free shared buff/cache available
Mem: 1743 798 513 203 799 944
Swap: 2063 102 1961
[root@Docker-node1 ~]# rm -rf /dev/shm/bigfile
[root@Docker-node1 ~]# echo 209715200 > /sys/fs/cgroup/memory/x1/memory.memsw.limit_in_bytes
[root@Docker-node1 ~]# cgexec -g memory:x1 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=180
记录了180+0 的读入
记录了180+0 的写出
188743680字节(189 MB,180 MiB)已复制,0.074551 s,2.5 GB/s
[root@Docker-node1 ~]# cgexec -g memory:x1 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=190
记录了190+0 的读入
记录了190+0 的写出
199229440字节(199 MB,190 MiB)已复制,0.0810031 s,2.5 GB/s
[root@Docker-node1 ~]# cgexec -g memory:x1 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=200
已杀死
cgexec -g memory:doceker/容器id -g表示使用指定控制器类型
7.1.3 限制docker的磁盘io
[root@Docker-node1 ~]# docker run -it --rm \
> --device-write-bps \ #指定容器使用磁盘io的速率
> /dev/nvme0n1:30M \ #/dev/nvme0n1是指定系统的磁盘,30M即每秒30M数据
> ubuntu
root@4ad98187f759:/# 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.0442974 s, 2.4 GB/s
root@4ad98187f759:/# 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, 3.30654 s, 31.7 MB/s
root@4ad98187f759:/#
7.2 Docker的安全加固
7.2.1 Docker默认隔离性
在系统中运行容器,我们会发现资源并没有完全隔离开
#系统内存使用情况
[root@Docker-node1 ~]# free -m
total used free shared buff/cache available
Mem: 1743 860 328 205 925 882
Swap: 2063 0 2063
#容器中内存使用情况
[root@Docker-node1 ~]# docker run --rm --memory 200M -it ubuntu
root@26abb6ee3a48:/# free -m
total used free shared buff/cache available
Mem: 1743 887 296 205 931 856
Swap: 2063 0 2063
root@26abb6ee3a48:/#
#虽然我们限制了容器的内容使用情况,但是查看到的信息依然是系统中内存的使用信息,并没有隔离开
7.2.2 解决Docker的默认隔离性
LXCFS 是一个为 LXC(Linux Containers)容器提供增强文件系统功能的工具。
主要功能
1. 资源可见性:
LXCFS 可以使容器内的进程看到准确的 CPU、内存和磁盘 I/O 等资源使用信息。在没有 LXCFS
时,容器内看到的资源信息可能不准确,这会影响到在容器内运行的应用程序对资源的评估和
管理。
2. 性能监控:
方便对容器内的资源使用情况进行监控和性能分析。通过提供准确的资源信息,管理员和开发
人员可以更好地了解容器化应用的性能瓶颈,并进行相应的优化。
安装lxcfs
[root@Docker-node1 ~]# yum install lxc-libs-4.0.12-1.el9.x86_64.rpm -y
[root@Docker-node1 ~]# yum install lxc-templates-4.0.12-1.el9.x86_64.rpm -y
[root@Docker-node1 ~]# yum install lxcfs-5.0.4-1.el9.x86_64.rpm -y
运行lxcfs并解决容器隔离性
[root@Docker-node1 ~]# lxcfs /var/lib/lxcfs &
[root@Docker-node1 ~]# cd /var/lib/lxcfs/
[root@Docker-node1 lxcfs]# ls
cgroup proc sys
[root@Docker-node1 lxcfs]# cd
[root@Docker-node1 ~]# docker run -it -m 256m \ #-m等于--memory
> -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@dfb765931ec0:/# free -m
total used free shared buff/cache available
Mem: 256 1 254 0 0 254
Swap: 512 0 512
root@dfb765931ec0:/#
7.2.3 容器特权
在容器中默认情况下即使我是容器的超级用户也无法修改某些系统设定,比如网络
[root@Docker-node1 ~]# docker run -it --rm --name test busybox
/ # 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:13 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:1782 (1.7 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)
/ # ip a a 1.1.1.1/24 dev eth0
ip: RTNETLINK answers: Operation not permitted
/ # whoami
root
/ #
这是因为容器使用的很多资源都是和系统真实主机公用的,如果允许容器修改这些重要资源,系统的稳定性会变的非常差
但是由于某些需要求,容器需要控制一些默认控制不了的资源,如何解决此问题,这时我们就要设置容器特权
[root@Docker-node1 ~]# docker run -it --rm --name test --privileged busybox
/ # 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:13 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:1782 (1.7 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)
/ # whoami
root
/ # ip a a 1.1.1.1/24 dev eth0
/ # ip ad
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
31: eth0@if32: <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 1.1.1.1/24 scope global eth0
valid_lft forever preferred_lft forever
/ #
#如果添加了--privileged 参数开启容器,容器获得权限近乎于宿主机的root用户
如果添加了--privileged 参数开启容器,容器获得权限近乎于宿主机的root用户
7.2.4 容器特权的白名单
--privileged=true 的权限非常大,接近于宿主机的权限,为了防止用户的滥用,需要增加限制,只提供给容器必须的权限。此时Docker 提供了权限白名单的机制,使用--cap-add添加必要的权限
capabilities手册地址:http://man7.org/linux/man-pages/man7/capabilities.7.html
#限制容器对网络有root权限,NET_ADMIN为可以修改网络参数
[root@Docker-node1 ~]# docker run -it --rm --name test --cap-add NET_ADMIN busybox
/ # whoami
root
/ # fdisk -l #无法管理磁盘
/ # 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:2198 (2.1 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)
/ # ip a a 1.1.1.1/24 dev eth0 #网络可以设定
/ # ip ad
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
33: eth0@if34: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
inet 1.1.1.1/24 scope global eth0
valid_lft forever preferred_lft forever
/ #
八容器编排工具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-node1 ~]# cd test
[root@Docker-node1 test]# vim docker-compose.yml
#- "80:80"表示一个列表
services:
web:
image: nginx:latest
ports:
- "80:80"
- "443:443"
testnode:
image: busybox:latest
command: ["/bin/sh","-c","sleep 10000"]
如果没有指定文件,Docker Compose会去docker-compose.yml查找命令
以下是一些 Docker Compose 常用命令:
一、服务管理
1. docker-compose up :
启动配置文件中定义的所有服务。
可以使用 -d 参数在后台启动服务。
可以使用-f 来指定yml文件
例如: docker compose up -d 。
[root@Docker-node1 test]# docker compose up -d
[+] Running 2/2
✔ Container test-web-1 Started 0.3s
✔ Container test-testnode-1 Running 0.0s
[root@Docker-node1 test]#
#如果没有docker-compose.yml文件,需要-f指定文件启动,停止删除等都是这样操作
[root@Docker-node1 test]# mv docker-compose.yml zhang.yml
[root@Docker-node1 test]# docker compose up -d
[+] Running 1/2
✔ Container root-testnode-1 Started 0.4s
⠸ Container root-web-1 Starting 0.4s
Error response from daemon: driver failed programming external connectivity on endpoint root-web-1 (c81d691678a3c3e2fc8e2ba93612b64c8a32c31d531ba636bf8d96c44bd40738): Bind for 0.0.0.0:80 failed: port is already allocated
[root@Docker-node1 test]# docker compose -f zhang.yml up -d
[+] Running 2/0
✔ Container test-web-1 Running 0.0s
✔ Container test-testnode-1 Running 0.0s
[root@Docker-node1 test]#
2. docker compose down :
停止并删除配置文件中定义的所有服务以及相关的网络和存储卷。
[root@Docker-node1 test]# mv zhang.yml docker-compose.yml
[root@Docker-node1 test]# docker compose down
[+] Running 3/3
✔ Container test-web-1 Removed 0.2s
✔ Container test-testnode-1 Removed 10.1s
✔ Network test_default Removed 0.1s
[root@Docker-node1 test]#
3. docker-compose start :
启动已经存在的服务,但不会创建新的服务。
[root@Docker-node1 test]# docker compose start
[+] Running 2/2
✔ Container test-testnode-1 Started 0.2s
✔ Container test-web-1 Started 0.3s
[root@Docker-node1 test]#
4. docker-compose stop :
停止正在运行的服务
[root@Docker-node1 test]# docker compose stop
[+] Stopping 2/2
✔ Container test-web-1 Stopped 0.1s
✔ Container test-testnode-1 Stopped 10.1s
[root@Docker-node1 test]#
5. docker-compose restart :
重启服务
[root@Docker-node1 test]# docker compose restart
[+] Restarting 2/2
✔ Container test-testnode-1 Started 10.3s
✔ Container test-web-1 Started 0.4s
[root@Docker-node1 test]#
二、服务状态查看
1. docker-compose ps :
。列出正在运行的服务以及它们的状态,包括容器ID、名称、端口映射等信息。
[root@Docker-node1 test]# docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
test-testnode-1 busybox:latest "/bin/sh -c 'sleep 1…" testnode 6 minutes ago Up 6 minutes
2. docker-compose logs :
查看服务的日志输出。可以指定服务名称来查看特定服务的日志
[root@docker test]# docker compose logs
三、构建和重新构建服务(了解)
1. docker-compose build :
构建配置文件中定义的服务的镜像。可以指定服务名称来只构建特定的服务。
[root@Docker-node1 test]# rm -rf /root/docker/*
[root@Docker-node1 test]# cd /root/docker/
[root@Docker-node1 docker]# ls
[root@Docker-node1 docker]# vim Dockerfile
FROM busybox:latest
RUN touch /hahafile1
[root@Docker-node1 docker]# vim haha
FROM busybox:latest
RUN touch /hahafile2
[root@Docker-node1 docker]# cd ../test/
[root@Docker-node1 test]# vim docker-compose.yml
services:
test1:
image: test1 #生成镜像名称
build:
context: /root/docker #指定Dockerfile位置
dockerfile: Dockerfile #指定Dockerfile名字
command: ["/bin/sh","-c","sleep 100000"]
container_name: haha1 #容器的名称
test2:
image: test2
build:
context: /root/docker
dockerfile: haha
command: ["/bin/sh","-c","sleep 100000"]
container_name: haha2
#构建services中的所有
[root@Docker-node1 test]# docker compose build
[+] Building 0.7s (12/12) FINISHED docker:default
=> [test1 internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 78B 0.0s
=> [test2 internal] load build definition from haha 0.0s
=> => transferring dockerfile: 72B 0.0s
=> [test1 internal] load metadata for docker.io/library/busybox:latest 0.0s
=> [test2 internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [test1 internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> CACHED [test1 1/2] FROM docker.io/library/busybox:latest 0.0s
=> [test1 2/2] RUN touch /hahafile1 0.6s
=> [test2 2/2] RUN touch /hahafile2 0.6s
=> [test2] exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:03def4df888d5212ee14214ca74be680087253b81f9a8a5cd2cc33 0.0s
=> => naming to docker.io/library/test2 0.0s
=> [test1] exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:93166bd0a5506dcb552add39fddc5948c9aa51aeff03d27eb41603 0.0s
=> => naming to docker.io/library/test1 0.0s
=> [test2] resolving provenance for metadata file 0.0s
=> [test1] resolving provenance for metadata file 0.0s
#构建services中的test1
[root@Docker-node1 test]# docker compose build test1
[+] Building 0.0s (7/7) FINISHED docker:default
=> [test1 internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 78B 0.0s
=> [test1 internal] load metadata for docker.io/library/busybox:latest 0.0s
=> [test1 internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [test1 1/2] FROM docker.io/library/busybox:latest 0.0s
=> CACHED [test1 2/2] RUN touch /hahafile1 0.0s
=> [test1] exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:93166bd0a5506dcb552add39fddc5948c9aa51aeff03d27eb41603 0.0s
=> => naming to docker.io/library/test1 0.0s
=> [test1] resolving provenance for metadata file 0.0s
[root@Docker-node1 test]#
2. docker-compose up --build :
启动服务并在启动前重新构建镜像。
[root@Docker-node1 test]# docker compose up -d
[+] Running 3/3
✔ Network test_default Created 0.0s
✔ Container haha1 Started 0.6s
✔ Container haha2 Started 0.6s
[root@Docker-node1 test]#
[root@docker test]# docker compose up --build #会先构建镜像后启动容器
四、其他操作
1. docker compose exec :
在正在运行的服务容器中执行命令。
[root@Docker-node1 test]# vim test.yml
services:
test:
image: busybox
command: ["/bin/sh","-c","sleep 3000"]
restart: always
container_name: busybox1
[root@Docker-node1 test]# docker compose -f test.yml up -d
[+] Running 2/2
✔ Network test_default Created 0.1s
✔ Container busybox1 Started 0.3s
[root@Docker-node1 test]# docker compose -f test.yml exec test sh
/ #
2. docker compose pull :
拉取配置文件中定义的服务所使用的镜像。
[root@Docker-node1 test]# docker compose -f test.yml pull
[+] Pulling 2/2
✔ test Pulled
✔ ec562eabd705 Pull complete
3. docker compose config :
验证并查看解析后的 Compose 文件内容
[root@Docker-node1 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
#如果没有问题不打印语法
[root@Docker-node1 test]# docker compose -f test.yml config -q
8.3 Docker Compose 的yml文件
Docker Compose 的 YAML 文件用于定义和配置多容器应用程序的各个服务。以下是一个基本的
Docker Compose YAML 文件结构及内容解释:
一、服务(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 端口。
[root@Docker-node1 test]# vim docker-compose.yml
services:
web:
image: nginx
container_name: webserver #指定容器名称
restart: always #docekr容器自动启动
expose:
- 1234 #指定容器暴露那些端口,些端口仅对链接的服务可见,不会映射到主机的端口
ports:
- "80:80" #把本机的端口映射到容器的端口
[root@Docker-node1 test]# docker compose up -d
[+] Running 2/2
? Network test_default Created 0.1s
? Container webserver Started 0.3s
[root@Docker-node1 test]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0eb130243d88 nginx "/docker-entrypoint.…" 10 seconds ago Up 9 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp, 1234/tcp webserver
[root@Docker-node1 test]#
4. 环境变量(environment):
为容器设置环境变量,可以在容器内部的应用程序中使用。例如, VAR1: value1 设置环境变量 VAR1 的值为 value1
[root@Docker-node1 test]# vim docker-compose.yml
services:
web:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: redhat
5. 存储卷(volumes):
将主机上的目录或文件挂载到容器中,以实现数据持久化或共享。例如, -
/host/data:/container/data 将主机上的 /host/data 目录挂载到容器内的
/container/data 路径
[root@Docker-node1 test]# vim docker-compose.yml
services:
test:
image: busybox
command: ["/bin/sh","-c","sleep 3000"]
restart: always
container_name: busybox1
volumes:
- /etc/passwd:/tmp/passwd:ro #只读挂在本地文件到指定位置,/etc/passwd本机文件,/tmp/passwd容器文件
6. 网络(networks):
将服务连接到特定的网络,以便不同服务的容器可以相互通信
[root@Docker-node1 test]# vim docker-compose.yml
services:
test:
image: busybox:latest
command: ["/bin/sh","-c","sleep 3000"]
restart: always
container_name: haha
network_mode: bridge #使用本机自带bridge网络
[root@Docker-node1 test]# docker compose up -d
[root@Docker-node1 test]# docker network ls
NETWORK ID NAME DRIVER SCOPE
f36105d06285 bridge bridge local
209f019ce5de host host local
c4b671ab8b9d none null local
[root@Docker-node1 test]# docker exec -it haha sh
/ # 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: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:2378 (2.3 KiB) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
/ #
#自定义网络
[root@Docker-node1 test]# vim docker-compose.yml
services:
test:
image: busybox:latest
command: ["/bin/sh","-c","sleep 3000"]
restart: always
container_name: haha
networks:
- mynet1
- mynet2
networks:
mynet1:
driver: bridge
mynet2:
driver: bridge
[root@Docker-node1 test]# docker compose up -d
[+] Running 3/3
? Network test_mynet2 Created 0.0s
? Network test_mynet1 Created 0.1s
? Container haha Started 0.6s
[root@Docker-node1 test]# docker exec -it haha sh
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:15:00:02
inet addr:172.21.0.2 Bcast:172.21.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:39 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:5808 (5.6 KiB) TX bytes:0 (0.0 B)
eth1 Link encap:Ethernet HWaddr 02:42:AC:14:00:02
inet addr:172.20.0.2 Bcast:172.20.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:38 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:5671 (5.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)
/ #
7. 命令(command):
覆盖容器启动时默认执行的命令。例如, command: python app.py 指定容器启动时运行
python app.py 命令
[root@docker test]# vim busybox.yml
services:
web:
image: busybox
container_name: busybox
command: ["/bin/sh","-c","sleep10000000"]
二、网络(networks)
定义 Docker Compose 应用程序中使用的网络。可以自定义网络名称和驱动程序等属性。
默认情况下docker compose 在执行时会自动建立网路
[root@Docker-node1 test]# vim docker-compose.yml
services:
test:
image: busybox:latest
container_name: test
command: ["/bin/sh","-c","sleep 10000"]
network_mode: default #注意使用bridge的时候要用network_mode而不是networks
test2:
image: busybox:latest
container_name: test2
command: ["/bin/sh","-c","sleep 10000"]
networks:
- mynet1
test3:
image: busybox:latest
container_name: test3
command: ["/bin/sh","-c","sleep 10000"]
networks:
- mynet2
networks:
mynet1:
driver: bridge #使用桥接驱动,也可以使用macvlan用于跨主机连接
default:
external: true #不建立新的网络而使用外部资源
name: bridge #指定外部资源网络名字
mynet2:
ipam:
driver: default
config:
- subnet: 172.26.0.0/24
gateway: 172.26.0.254
[root@Docker-node1 test]# docker compose up -d
[+] Running 5/5
✔ Network test_mynet1 Created 0.1s
✔ Network test_mynet2 Created 0.1s
✔ Container test2 Started 0.7s
✔ Container test3 Started 0.6s
✔ Container test Started
[root@Docker-node1 test]# docker network ls
NETWORK ID NAME DRIVER SCOPE
f36105d06285 bridge bridge local
209f019ce5de host host local
c4b671ab8b9d none null local
539647ae06ed test_mynet1 bridge local
04e37f2f67f3 test_mynet2 bridge local
三、存储卷(volumes)
定义 Docker Compose 应用程序中使用的存储卷。可以自定义卷名称和存储位置等属性。
services:
test:
image: busybox:latest
container_name: test
command: ["/bin/sh","-c","sleep 10000"]
volumes:
- data:/data #挂在data卷
volumes:
data:
name: hahaha #指定建立卷的名字
删除的话不会删除已经保存在本机的data目录
8.4 企业示例
利用容器编排完成haproxy和nginx负载均衡架构实施
#生成haporxy配置文件
[root@Docker-node1 test]# mkdir /var/lib/docker/volumes/conf
[root@Docker-node1 test]# dnf install haproxy -y --downloadonly --downloaddir=/mnt/
[root@Docker-node1 mnt]# rpm2cpio haproxy-2.4.22-3.el9_3.x86_64.rpm | cpio -id
[root@Docker-node1 mnt]# ls
etc hahafile haproxy-2.4.22-3.el9_3.x86_64.rpm hgfs usr var
[root@Docker-node1 mnt]# cd etc/
[root@Docker-node1 etc]# ls
haproxy logrotate.d sysconfig
[root@Docker-node1 etc]# cd haproxy/
[root@Docker-node1 haproxy]# ls
conf.d haproxy.cfg
[root@Docker-node1 haproxy]# cp haproxy.cfg /var/lib/docker/volumes/conf/
#编辑haproxy配置文件
[root@Docker-node1 haproxy]# vim /var/lib/docker/volumes/conf/haproxy.cfg
listen webcluster
bind *:80
balance roundrobin
server web1 webserver1:80 check inter 3 fall 3 rise 5
server web2 webserver2:80 check inter 3 fall 3 rise 5
[root@Docker-node1 haproxy]# cd /root/test/
#导入haproxy镜像
[root@Docker-node1 test]# docker load -i haproxy-2.3.tar.gz
#编写yml文件
[root@Docker-node1 test]# vim haproxy.yml
services:
web1:
image: nginx:latest
container_name: webserver1
restart: always
expose:
- 80
volumes:
- data_web1:/usr/share/nginx/html
networks:
- internel
web2:
image: nginx:latest
container_name: webserver2
restart: always
expose:
- 80
volumes:
- data_web2:/usr/share/nginx/html
networks:
- internel
haproxy:
image: haproxy:2.3
container_name: haproxy
restart: always
ports:
- "80:80"
volumes:
- /var/lib/docker/volumes/conf/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
networks:
- internel
- extrnal
networks:
internel:
driver: bridge
extrnal:
driver: bridge
volumes:
data_web1:
name: data_web1
data_web2:
name: data_web2
#启动
[root@Docker-node1 test]# docker compose -f haproxy.yml up -d
[+] Running 7/7
✔ Network test_internel Created 0.1s
✔ Network test_extrnal Created 0.1s
✔ Volume "data_web2" Created 0.0s
✔ Volume "data_web1" Created 0.0s
✔ Container webserver1 Started 0.7s
✔ Container webserver2 Started 0.8s
✔ Container haproxy Started 0.8s
[root@Docker-node1 test]# echo webserver1 > /var/lib/docker/volumes/data_web1/_data/
-bash: /var/lib/docker/volumes/data_web1/_data/: 是一个目录
[root@Docker-node1 test]# echo webserver1 > /var/lib/docker/volumes/data_web1/_data/index.html
[root@Docker-node1 test]# echo webserver2 > /var/lib/docker/volumes/data_web2/_data/index.html
#测试
[root@Docker-node1 test]# curl 172.25.254.100
webserver1
[root@Docker-node1 test]# curl 172.25.254.100
webserver2
[root@Docker-node1 test]# curl 172.25.254.100
webserver1
[root@Docker-node1 test]# curl 172.25.254.100
webserver2
编写haproxy的配置文件
编写yml文件
启动
测试