目录
(1)官网https://hub.docker.com/进行注册登录
(1)CNM(Container Network Model)
4、数据卷容器(Data Volume Container)
5、bind mount 数据卷和docker managed 数据卷的对比
服务名称(service1_name/service2_name 等)
一、Docker简介及部署方法
1、Docker简介
Docker是管理容器的引擎,为应用打包、部署平台,而非单纯的虚拟化技术
它具有以下几个重要特点和优势:
- 1. 轻量级虚拟化
- 2. 一致性
- 3. 可移植性
- 4. 高效的资源利用
- 5. 易于部署和扩展
docker与虚拟化的对比
虚拟机 | docker容器 | |
操作系统 | 宿主机上运行虚拟机OS | 共享宿主机OS |
存储 | 镜像较大(GB) | 镜像小(MB) |
性能 | 操作系统额外的cpu、内存消耗 | 几乎无性能损耗 |
移植性 | 笨重、与虚拟化技术耦合度高 | 轻量、灵活迁移 |
隔离性 | 完全隔离 | 安全隔离 |
部署 | 慢、分钟级 | 快速、秒级 |
运行密度 | 一般几十个 | 单机支持上千容器 |
2、rhel9部署docker
(1)容器工作方法
(2)部署
1)配置软件仓库
[root@docker-node1 ~]# cd /etc/yum.repos.d/
[root@docker-node1 yum.repos.d]# ls
redhat.repo rhel9.repo
[root@docker-node1 yum.repos.d]# vim docker.repo
[root@docker-node1 yum.repos.d]# cat dockere.repo
[docker]
name=docker
baseurl=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/rhel/9/x86_64/stable/
gpgcheck=0
2)安装docker-ce
法一
[root@docker-node1 yum.repos.d]# yum search docker-ce
[root@docker-node1 yum.repos.d]# yum install -y docker-ce.x86_64
法二
[root@docker-node1 ~]# ls
anaconda-ks.cfg Desktop docker.tar.gz Documents Downloads Music Pictures Public Templates Videos zuoyedir
[root@docker-node1 ~]# tar zxf docker.tar.gz
[root@docker-node1 ~]# ls
anaconda-ks.cfg docker-ce-cli-27.1.2-1.el9.x86_64.rpm Downloads Videos
containerd.io-1.7.20-3.1.el9.x86_64.rpm docker-ce-rootless-extras-27.1.2-1.el9.x86_64.rpm Music zuoyedir
Desktop docker-compose-plugin-2.29.1-1.el9.x86_64.rpm Pictures
docker-buildx-plugin-0.16.2-1.el9.x86_64.rpm docker.tar.gz Public
docker-ce-27.1.2-1.el9.x86_64.rpm Documents Templates
[root@docker-node1 ~]# dnf install *.rpm -y
[root@docker-node1 ~]# systemctl enable --now docker
Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /usr/lib/systemd/system/docker.service.
[root@docker-node1 ~]# docker info
https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors
# 配置镜像加速器
[root@docker-node1 ~]# cd /etc/docker/
[root@docker-node1 docker]# vim daemon.json
[root@docker-node1 docker]# cat daemon.json
{
"registry-mirrors": ["https://y3w6d9eb.mirror.aliyuncs.com"]
}
二、Docker的基本操作
1、Docker镜像管理
(1)搜索镜像
[root@docker-node1 ~]# docker search nginx
NAME DESCRIPTION STARS OFFICIAL
nginx Official build of Nginx. 20126 [OK]
参数 | 说明 |
NAME | 镜像名称 |
DESCRIPTION | 镜像说明 |
STARS | 点赞数量 |
OFFICIAL | 是否是官方的 |
(2)拉取镜像
[root@docker-node1 ~]# docker pull busybox
[root@docker-node1 ~]# ls
anaconda-ks.cfg docker-ce-rootless-extras-27.1.2-1.el9.x86_64.rpm Music
busybox-latest.tar.gz docker-compose-plugin-2.29.1-1.el9.x86_64.rpm nginx-latest.tar.gz
containerd.io-1.7.20-3.1.el9.x86_64.rpm docker.tar.gz Pictures
Desktop Documents Public
docker-buildx-plugin-0.16.2-1.el9.x86_64.rpm Downloads Templates
docker-ce-27.1.2-1.el9.x86_64.rpm game2048.tar.gz Videos
docker-ce-cli-27.1.2-1.el9.x86_64.rpm mario.tar.gz zuoyedir
[root@docker-node1 ~]# docker load -i game2048.tar.gz
[root@docker-node1 ~]# docker load -i mario.tar.gz
[root@docker-node1 ~]# docker load -i nginx-latest.tar.gz
[root@docker-node1 ~]# docker load -i busybox-latest.tar.gz
[root@docker-node1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 5ef79149e0ec 13 days ago 188MB
busybox latest 65ad0d468eb1 15 months ago 4.26MB
timinglee/game2048 latest 19299002fdbe 7 years ago 55.5MB
timinglee/mario latest 9a35a9e43e8c 8 years ago 198MB
(3)查看镜像信息
[root@docker-node1 ~]# docker image inspect nginx:latest
查看镜像结构
(4)导出镜像
-o:指定导出镜像的位置
可以同时导出多个镜像到一个文件中,指定.tar.gz 可以导出并压缩
[root@docker-node1 ~]# docker image save nginx:latest -o nginx-latest.tar.gz
#保存所有镜像
[root@docker-node1 ~]# docker save `docker images | awk 'NR>1{print $1":"$2}'` -o images.tar.gz
(5)删除镜像
[root@docker-node1 ~]# docker rmi nginx:latest
[root@docker-node1 ~]# docker rmi `docker images | awk 'NR>1{print $1":"$2}'`
(6)镜像测试
[root@docker-node1 ~]# docker run -d --rm --name webserver -p 80:80 nginx
3c2ade3d9c9258c7c571a36f8a9aa5e919f6844fdc2fcc0508ed34e356e72982
[root@docker-node1 ~]#
[root@docker-node1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3c2ade3d9c92 nginx "/docker-entrypoint.…" 10 seconds ago Up 9 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp webserver
[root@docker-node1 ~]# docker rm -f webserver
webserver
[root@docker-node1 ~]# docker run -d --rm --name game1 -p 80:8080 timinglee/mario:latest
3feb451086de8c9ce53df2ab2354f504a799d6efd37ef5da03b1a5598d7631be
[root@docker-node1 ~]# docker rm -f game1
game1
2、容器的常用操作
(1)启动容器
[root@docker-node1 ~]# docker run -d --name mario -p 80:8080 timinglee/mario
-d #后台运行
-i #交互式运行
-t #打开一个终端
--name #指定容器名称
-p #端口映射 -p 80:8080 把容器8080端口映射到本机80端口
--rm #容器停止自动删除容器
--network #指定容器使用的网络
[root@docker-node1 ~]# docker run -it --name test busybox # #进入到容器中,按<ctrl>+<d>退出并停止容器,#按<ctrl>+<pq>退出但不停止容器
/ #
/ # ls
bin dev etc home lib lib64 proc root sys tmp usr var
/ # date
Wed Aug 28 10:02:58 UTC 2024
/ #
/ # exit
[root@docker-node1 ~]# date
Wed Aug 28 06:03:05 PM CST 2024
# 重新进入容器
[root@docker-node1 ~]# docker attach test
/ #
/ #
/ #
# 删除容器
[root@docker-node1 ~]# docker rm test
test
#在容器中执行命令
[root@docker-node1 ~]# docker start test
[root@docker-node1 ~]# docker exec -it test ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:03
inet addr:172.17.0.3 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:16 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:2086 (2.0 KiB) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
(2)查看容器运行信息
#查看当前运行容器
[root@docker-node1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
edb72465fb76 timinglee/mario "python3 -m http.ser…" 11 minutes ago Up 11 minutes 0.0.0.0:80->8080/tcp, :::80->8080/tcp mario
#查看所有容器
[root@docker-node1 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4e676f3fc287 busybox "sh" 8 seconds ago Exited (0) 3 seconds ago test
edb72465fb76 timinglee/mario "python3 -m http.ser…" 11 minutes ago Up 11 minutes 0.0.0.0:80->8080/tcp, :::80->8080/tcp mario
#查看容器运行的详细信息
[root@docker-node1 ~]# docker inspect busybox
(3)停止和运行容器
容器内的第一个进程必须一直处于运行的状态,否则这个容器,就会处于退出状态!
#停止容器
[root@docker-node1 ~]# docker stop test
#杀死容器,可以使用信号
[root@docker-node1 ~]# docker kill test
#开启停止的容器
[root@docker-node1 ~]# docker start test
test
[root@docker-node1 ~]# docker ps -a # 查看是否停止开启
(4)删除容器
#删除停止的容器
[root@docker-node1 ~]# docker rm test
#删除运行的容器
[root@docker-node1 ~]# docker rm -f test
#删除所有停止的容器
[root@docker-node1 ~]# docker container prune -f
#删除建立所有失败的容器
[root@docker-node1 docker]# docker rmi `docker images | awk '/none/{print $3}'`
#通配符匹配删除容器
[root@docker-node1 docker]# docker rmi busybox:v{1,2}
Untagged: busybox:v1
Deleted: sha256:4f5a1e92b339f1982ff0c33e2d2a64336ecbe7259c54b9b76818add068fd5f60
Deleted: sha256:36ba2277cefa7e88834017d08732f9b5cfc60a6f1602e0e06774185972999471
Untagged: busybox:v2
Deleted: sha256:f9ed1b274e05538f5797574ecfc25aa68ce2b24055b018f05131f96f7c4c74a8
(5)容器内容提交
- 默认情况下,容器被删除后,在容器中的所有操作都会被清理,包括要保存的文件
- 如果想永久保存,那么需要把动作提交,提交后会生成新的镜像
- 当在运行新镜像后即可看到提交的内容
[root@docker-node1 ~]# docker run -it --name test busybox
/ # touch zx-file
/ # ls
bin dev etc home lib lib64 proc root sys tmp usr var zx-file
/ # exit
[root@docker-node1 ~]# docker rm test
test
[root@docker-node1 ~]# docker run -it --name test busybox
/ # ls
bin dev etc home lib lib64 proc root sys tmp usr var
/ # [root@docker-node1 ~]#
[root@docker-node1 ~]# docker commit -m "add zx-file" test busybox:v1
sha256:4f5a1e92b339f1982ff0c33e2d2a64336ecbe7259c54b9b76818add068fd5f60
[root@docker-node1 ~]#
[root@docker-node1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
busybox v1 4f5a1e92b339 5 seconds ago 4.26MB
nginx latest 5ef79149e0ec 13 days ago 188MB
busybox latest 65ad0d468eb1 15 months ago 4.26MB
timinglee/game2048 latest 19299002fdbe 7 years ago 55.5MB
timinglee/mario latest 9a35a9e43e8c 8 years ago 198MB
[root@docker-node1 ~]#
[root@docker-node1 ~]# docker image history busybox:v1
(6)系统中的文件和容器中的文件传输
#把容器中的文件复制到本机
[root@docker-node1 ~]# docker cp test:/zx-file /root
Successfully copied 1.54kB to /root
#把本机文件复制到容器中
[root@docker-node1 ~]# docker cp zx-file-new test:/root
Successfully copied 1.54kB to test:/root
[root@docker-node1 ~]# docker attach test
/ # cd root/
~ # ls
zx-file-new
(7)查询容器内部日志
[root@docker-node1 ~]# docker logs test
三、docker镜像构建
1、docker镜像结构
- 共享宿主机的kernel
- base镜像提供的是最小的Linux发行版
- 同一docker主机支持运行多种Linux发行版
- 采用分层结构的最大好处是:共享资源
2、镜像运行的基本原理
- Copy-on-Write 可写容器层
- 容器层以下所有镜像层都是只读的
- docker从上往下依次查找文件
- 容器层保存镜像变化的部分,并不会对镜像本身进行任何修改
- 一个镜像最多127层
3、镜像获得方式
- 基本镜像通常由软件官方提供
- 企业镜像可以用官方镜像+Dockerfile来生成
- 系统关于镜像的获取动作有两种:
- docker pull 镜像地址
- docker load –i 本地镜像包
4、镜像构建
(1)构建参数
FROM | 指定base镜像 eg:FROM busybox:version |
COPY | 复制文件 eg:COPY file /file 或者 COPY [“file”,”/”] |
MAINTAINER | 指定作者信息,比如邮箱 eg:MAINTAINER [email protected] 在最新版的docker中用LABEL KEY="VALUE"代替 |
ADD | 功能和copy相似,指定压缩文件或url eg: ADD test.tar /mnt 或者 ADD http://ip/test.tar /mnt |
ENV | 指定环境变量 eg:ENV FILENAME test |
EXPOSE | 暴漏容器端口 eg:EXPOSE 80 |
VOLUME | 申明数据卷,通常指数据挂载点 eg:VOLUME [“/var/www/html”] |
WORKDIR | 切换路径 eg:WORKDIR /mnt |
RUN | 在容器中运行的指令 eg: touch file |
CMD | 在启动容器时自动运行动作可以被覆盖 eg:CMD echo $FILENAME 会调用 shell解析 eg:CMD [“/bin/sh”,”-c”,“echo $FILENAME”] 不调用shell解析 |
ENTRYPOINT | 和CMD功能和用法类似,但动作不可被覆盖 |
[root@docker-node1 ~]# mkdir docker/
[root@docker-node1 ~]# cd docker/
[root@docker-node1 docker]# touch zxfile
[root@docker-node1 docker]# vim Dockerfile
[root@docker-node1 docker]# cat Dockerfile
FROM busybox:latest
LABEL [email protected]
COPY zxfile /
[root@docker-node1 docker]# docker build -t busybox:v2 .
[root@docker-node1 docker]# docker history busybox:v2
IMAGE CREATED CREATED BY SIZE COMMENT
f9ed1b274e05 11 minutes ago COPY zxfile / # buildkit 0B buildkit.dockerfile.v0
<missing> 11 minutes ago LABEL [email protected] 0B buildkit.dockerfile.v0
<missing> 15 months ago BusyBox 1.36.1 (glibc), Debian 12 4.26MB
(2)Dockerfile实例
1)建立构建目录,编写构建文件
[root@docker-node1 ~]# docker load -i /root/centos-7.tar.gz
174f56854903: Loading layer [==================================================>] 211.7MB/211.7MB
Loaded image: centos:7
[root@docker-node1 ~]# mkdir docker
[root@docker-node1 ~]# cd docker/
[root@docker-node1 docker]# cp ~/nginx-1.23.tar.gz .
[root@docker-node1 docker]# vim Dockerfile
[root@docker-node1 docker]# cat Dockerfile
FROM centos:7
ADD nginx-1.26.1.tar.gz /root
WORKDIR /root/nginx-1.26.1
RUN yum install -y gcc make pcre-devel openssl-devel
RUN ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_stub_status_module
RUN make
RUN make install
EXPOSE 80 443
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off"]
2)通过dockerfile生成镜像
[root@docker-node1 docker]# docker build -t webserver:v1 .
# 出现“=> ERROR [4/8] RUN yum install -y gcc make pcre-devel openssl-devel”错误时:新添7.9的ISO映像文件
[root@docker-node1 ~]# docker run -it --name centos centos:7
[root@docker-node1 ~]# mkdir -p /var/www/html/rhel7.9
[root@docker-node1 ~]# mount /dev/sr
sr0 sr1
[root@docker-node1 ~]# mount /dev/sr1 /var/www/html/rhel7.9/
mount: /var/www/html/rhel7.9: WARNING: source write-protected, mounted read-only.
[root@docker-node1 yum.repos.d]# yum install httpd -y
[root@docker-node1 yum.repos.d]# vim /etc/httpd/conf/httpd.conf # 更改端口为8888
[root@docker-node1 yum.repos.d]# systemctl start httpd
[root@docker-node1 ~]# docker attach centos
[root@9254e0ce5b5e /]# cd /etc/yum.repos.d/
[root@9254e0ce5b5e yum.repos.d]# ls
CentOS-Base.repo CentOS-Debuginfo.repo CentOS-Sources.repo CentOS-fasttrack.repo
CentOS-CR.repo CentOS-Media.repo CentOS-Vault.repo CentOS-x86_64-kernel.repo
[root@9254e0ce5b5e yum.repos.d]# rm -fr *
[root@9254e0ce5b5e yum.repos.d]# vi centos7.repo
[root@9254e0ce5b5e yum.repos.d]# cat centos7.repo
[centos7]
name=centos7
baseurl=http://172.17.0.1:8888/rhel7.9
gpgcheck=0
[root@docker-node1 ~]# docker commit -m "add repo" centos centos:repo
sha256:e651ad916be95747432b9082d6497e6498365d2fba1df1f6ca4e9dc932572b95
[root@docker-node1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos repo e651ad916be9 8 seconds ago 204MB
[root@9254e0ce5b5e yum.repos.d]# exit
exit
[root@docker-node1 ~]#
[root@docker-node1 ~]# docker rm centos
centos
[root@docker-node1 docker]# vim Dockerfile
[root@docker-node1 docker]# cat Dockerfile
FROM centos:repo
ADD nginx-1.26.1.tar.gz /root
WORKDIR /root/nginx-1.26.1
RUN yum install -y gcc make pcre-devel openssl-devel
RUN ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_stub_status_module
RUN make
RUN make install
EXPOSE 80 443
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off"]
若虚拟机安装docker后ip地址没了,修改Docker网络配置
[root@docker-node1 docker]# vim /etc/docker/daemon.json
[root@docker-node1 docker]# cat daemon.json
{
"bip":"172.17.0.1/16",
"registry-mirrors": ["https://y3w6d9eb.mirror.aliyuncs.com"]
}
[root@docker-node1 docker]# systemctl restart docker
[root@docker-node1 ~]# docker inspect centos # 查看名为centos的docker端口IP
[root@docker-node1 docker]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.214 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.158 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.097 ms
3)测试镜像可用性
[root@docker-node1 docker]# docker images webserver
REPOSITORY TAG IMAGE ID CREATED SIZE
webserver v1 5b17bdead0af About a minute ago 356MB
[root@docker-node1 docker]# docker history webserver:v1
IMAGE CREATED CREATED BY SIZE COMMENT
5b17bdead0af About a minute ago CMD ["/usr/local/nginx/sbin/nginx" "-g" "dae… 0B buildkit.dockerfile.v0
<missing> About a minute ago VOLUME [/usr/local/nginx/html] 0B buildkit.dockerfile.v0
<missing> About a minute ago EXPOSE map[443/tcp:{} 80/tcp:{}] 0B buildkit.dockerfile.v0
<missing> About a minute ago RUN /bin/sh -c make install # buildkit 6.11MB buildkit.dockerfile.v0
<missing> About a minute ago RUN /bin/sh -c make # buildkit 20.6MB buildkit.dockerfile.v0
<missing> 2 minutes ago RUN /bin/sh -c ./configure --prefix=/usr/loc… 78.9kB buildkit.dockerfile.v0
<missing> 2 minutes ago RUN /bin/sh -c yum install -y gcc make pcre-… 118MB buildkit.dockerfile.v0
<missing> 3 minutes ago WORKDIR /root/nginx-1.26.1 0B buildkit.dockerfile.v0
<missing> 3 minutes ago ADD nginx-1.26.1.tar.gz /root # buildkit 7.35MB buildkit.dockerfile.v0
<missing> 49 minutes ago /bin/bash 73B add repo
<missing> 2 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 2 years ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
<missing> 2 years ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB
4)查看容器详情
[root@docker-node1 docker]# docker inspect webserver:v1
5、镜像优化方案
(1)镜像优化策略
- 选择最精简的基础镜像
- 减少镜像的层数
- 清理镜像构建的中间产物
- 选择最精简的基础镜像
- 减少镜像的层数
- 清理镜像构建的中间产物
(2)镜像优化示例
方法一:缩减镜像层
[root@docker-node1 docker]# docker images webserver
REPOSITORY TAG IMAGE ID CREATED SIZE
webserver v1 5b17bdead0af 10 hours ago 356MB
[root@docker-node1 docker]# vim Dockerfile
[root@docker-node1 docker]# cat Dockerfile
FROM centos:repo
ADD nginx-1.26.1.tar.gz /root
WORKDIR /root/nginx-1.26.1
RUN yum install -y gcc make pcre-devel openssl-devel && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && ./configure --with-http_ssl_module --with-http_stub_status_module && make && make install && cd .. && rm -fr nginx1.23.3 && yum clean all
EXPOSE 80 443
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off"]
[root@docker-node1 docker]# docker build -t webserver:v2 .
方法二:多阶段构建
[root@docker-node1 docker]# vim Dockerfile
[root@docker-node1 docker]# docker build -t webserver:v3 .
[root@docker-node1 docker]# docker images webserver
[root@docker-node1 docker]# cat Dockerfile
FROM centos:repo AS build
ADD nginx-1.26.1.tar.gz /root
WORKDIR /root/nginx-1.26.1
RUN yum install -y gcc make pcre-devel openssl-devel && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && ./configure --with-http_ssl_module --with-http_stub_status_module && make && make install && cd .. && rm -fr nginx1.23.3 && yum clean all
FROM centos:repo
COPY --from=build /usr/local/nginx /usr/local/nginx
EXPOSE 80 443
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off"]
方法三:使用最精简镜像
[root@docker-node1 ~]# docker load -i nginx-1.23.tar.gz
[root@docker-node1 ~]# docker load -i debian11.tar.gz
[root@docker-node1 ~]# mkdir new
[root@docker-node1 ~]# cp nginx-1.23.tar.gz new/
[root@docker-node1 ~]# cp debian11.tar.gz new/
[root@docker-node1 ~]# cd new/
[root@docker-node1 new]# vim Dockerfile
[root@docker-node1 new]# cat Dockerfile
FROM nginx:1.23 AS base
ARG TIME_ZONE
RUN mkdir -p /opt/var/cache/nginx && \
cp -a --parents /usr/lib/nginx /opt && \
cp -a --parents /usr/share/nginx /opt && \
cp -a --parents /var/log/nginx /opt && \
cp -aL --parents /var/run /opt && \
cp -a --parents /etc/nginx /opt && \
cp -a --parents /etc/passwd /opt && \
cp -a --parents /etc/group /opt && \
cp -a --parents /usr/sbin/nginx /opt && \
cp -a --parents /usr/sbin/nginx-debug /opt && \
cp -a --parents /lib/x86_64-linux-gnu/ld-* /opt && \
cp -a --parents /usr/lib/x86_64-linux-gnu/libpcre* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libz.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libc* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libdl* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libpthread* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libcrypt* /opt && \
cp -a --parents /usr/lib/x86_64-linux-gnu/libssl.so.* /opt && \
cp -a --parents /usr/lib/x86_64-linux-gnu/libcrypto.so.* /opt && \
cp /usr/share/zoneinfo/${TIME_ZONE:-ROC} /opt/etc/localtime
FROM gcr.io/distroless/base-debian11
COPY --from=base /opt /
EXPOSE 80 443
ENTRYPOINT ["nginx", "-g", "daemon off;"]
[root@docker-node1 new]# docker build -t webserver:v4 .
四、docker 镜像仓库的管理
1、docker仓库
Docker 仓库(Docker Registry) 是用于存储和分发 Docker 镜像的集中式存储库。
它就像是一个大型的镜像仓库,开发者可以将自己创建的 Docker 镜像推送到仓库中,也可以从仓库中拉取所需的镜像。
Docker 仓库可以分为公共仓库和私有仓库:
- 公共仓库,如 Docker Hub,任何人都可以访问和使用其中的镜像。许多常用的软件和应用都有在 Docker Hub 上提供的镜像,方便用户直接获取和使用。 例如,您想要部署一个 Nginx 服务器,就可以从 Docker Hub 上拉取 Nginx 的镜像。
- 私有仓库则是由组织或个人自己搭建和管理的,用于存储内部使用的、不希望公开的镜像。 比如,一家企业为其特定的业务应用创建了定制化的镜像,并将其存储在自己的私有仓库中, 以保证安全性和控制访问权限。
通过 Docker 仓库,开发者能够方便地共享和复用镜像,加速应用的开发和部署过程
2、docker公有仓库
(1)官网https://hub.docker.com/进行注册登录
(2)登录信息保存位置
[root@docker-node1 ~]# cd .docker/
[root@docker-node1 .docker]# ls
buildx config.json
[root@docker-node1 .docker]# cat config.json
{
"auths": {
"https://index.docker.io/v1/": {
"auth": "MTIzNHp4OlpYenhjdmJubQ=="
}
}
}[root@docker-node1 .docker]#
(3)打标记上传docker
[root@docker-node1 ~]# docker tag webserver:v1 1234zx/webserver:v1
[root@docker-node1 ~]# docker push 1234zx/webserver:v1
3、docker仓库的工作原理
仓库中的三个角色
- index docker索引服务,负责并维护有关用户帐户、镜像的校验以及公共命名空间的信息。
- registry docker仓库,是镜像和图表的仓库,它不具有本地数据库以及不提供用户认证,通过Index Auth service的Token的方式进行认证
- Registry Client Docker充当registry客户端来维护推送和拉取,以及客户端的授权。
(1)pull原理
镜像拉取分为以下几步:
- docker客户端向index发送镜像拉去请求并完成与index的认证
- index发送认证token和镜像位置给dockerclient
- dockerclient携带token和根据index指引的镜像位置取连接registry
- Registry会根据client持有的token跟index核实身份合法性
- index确认此token合法性
- Registry会根据client的请求传递镜像到客户端
(2)push原理
镜像上传的步骤:
- client向index发送上传请求并完成用户认证
- index会发方token给client来证明client的合法性
- client携带index提供的token连接Registry
- Registry向index合适token的合法性
- index证实token的合法性
- Registry开始接收客户端上传过来的镜像
4、搭建docker的私有仓库
(1)下载Registry镜像
# 直接pull下载
[root@docker-node1 ~]# docker pull registry
# 镜像导入
[root@docker-node1 ~]# docker load -i registry.tag.gz
(2)开启Registry
[root@docker-node1 ~]# docker run -d -p 5000:5000 --restart=always --name registry registry
(3)上传镜像到仓库中
[root@docker-node1 ~]# vim /etc/docker/daemon.json
[root@docker-node1 ~]# cat /etc/docker/daemon.json
{
"bip":"172.17.0.1/16",
"registry-mirrors": ["https://y3w6d9eb.mirror.aliyuncs.com"],
"insecure-registries" : ["http://172.25.254.100:5000"]
}
[root@docker-node1 ~]# systemctl restart docker
#给要上传的镜像打标签
[root@docker-node1 ~]# docker tag busybox:latest 172.25.254.100:5000/busybox:latest
#docker在上传的过程中默认使用https,没有建立https认证需要的认证文件会报错,故在daemon.json文件中配置非加密端口
#上传镜像
[root@docker-node1 ~]# docker push 172.25.254.100:5000/busybox:latest
The push refers to repository [172.25.254.100:5000/busybox]
d51af96cf93e: Pushed
latest: digest: sha256:28e01ab32c9dbcbaae96cf0d5b472f22e231d9e603811857b295e61197e40a9b size: 527
# 查看镜像上传
[root@docker-node1 ~]# curl 172.25.254.100:5000/v2/_catalog
{"repositories":["busybox"]}
(4)为Registry提加密传输
将/etc/docker/daemon.json中的非加密端口去掉
[root@docker-node1 ~]# mkdir certs
[root@docker-node1 ~]# vim /etc/hosts # 添加解析reg.zx.org <--> 172.25.254.100
#生成认证key和证书
[root@docker-node1 ~]# openssl req -newkey rsa:4096 -nodes -sha256 -keyout certs/zx.org.key \
> -addext "subjectAltName = DNS:reg.zx.org" \
> -x509 -days 365 -out certs/zx.org.crt
.+.....................+...+..+..........+........+.+............+..+...+...+......+....+............+...+..+....+........+.............+..+...+...+......+.........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.+......+.+...+..+.+.....+..........+..............+...+...+.......+...+...+......+...+...+..............+.+........+.......+..+......+............+.........+.+..+...............+.......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.+............+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.....+........+...+...+....+........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*..+.+..+..........+...+...+.....+....+.....+.......+.....+...+.+.........+.....+.+......+.....+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.............+..........+..+.+............+...+..+.........+.........+......+....+.....+....+............+........+..........+...+.....+....+..............+......+.+...+............+..+......+.+...+......+...........+.....................+...+.......+..+..........+...........+.......+..+...+.........+.+..+..................+.......+........+............+.+.................+............+.+............+...+..+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:Shaanx
Locality Name (eg, city) [Default City]:XI'an
Organization Name (eg, company) [Default Company Ltd]:docker
Organizational Unit Name (eg, section) []:registry
Common Name (eg, your name or your server's hostname) []:reg.zx.org
Email Address []:[email protected]
[root@docker-node1 ~]# ls certs/
zx.org.crt zx.org.key
#启动registry仓库
[root@docker-node1 ~]# docker run -d -p 443:443 --restart=always --name registry -v /root/certs:/certs -e REGISTRY_HTTP_ADDR=0.0.0.0:443 -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/zx.org.crt -e REGISTRY_HTTP_TLS_KEY=/certs/zx.org.key registry:latest
[root@docker-node1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
980cb9c0faec registry:latest "/entrypoint.sh /etc…" 15 seconds ago Up 14 seconds 0.0.0.0:443->443/tcp, :::443->443/tcp, 5000/tcp registry
测试:
[root@docker-node1 ~]# docker tag registry:latest reg.zx.org/registry:latest
[root@docker-node1 ~]# mkdir /etc/docker/certs.d/reg.zx.org/ -p
[root@docker-node1 ~]# cp /root/certs/zx.org.crt /etc/docker/certs.d/reg.zx.org/ca.crt
[root@docker-node1 ~]# systemctl restart docker
[root@docker-node1 ~]# docker push reg.zx.org/registry:latest
[root@docker-node1 ~]# curl -k https://reg.zx.org/v2/_catalog
{"repositories":["registry"]}
(5)为仓库建立登陆认证
#安装建立认证文件的工具包
[root@docker-node1 ~]# dnf install httpd-tools -y
#建立认证文件,-B 强制使用最安全加密方式,默认用md5加密
[root@docker-node1 ~]# mkdir auth
[root@docker-node1 ~]# htpasswd -Bc auth/htpasswd zx
[root@docker-node1 ~]# cat auth/htpasswd
zx:$2y$05$M0B4z68fki4VdaqIIZVDt.Md/f3aPlDXDStgjTbUX39B.X7Skdl76
#添加认证到registry容器中
[root@docker-node1 ~]# docker run -d -p 443:443 --restart=always --name registry -v /root/certs:/certs -e REGISTRY_HTTP_ADDR=0.0.0.0:443 -e REGISTRY_HTTP_TLS_KEY=/certs/zx.org.key -v /root/auth:/auth -e REGISTRY_AUTH=htpasswd -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd registry
[root@docker-node1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b4faa3b0ac10 registry "/entrypoint.sh /etc…" 4 seconds ago Up 3 seconds 0.0.0.0:443->443/tcp, :::443->443/tcp, 5000/tcp registry
[root@local ~]# docker login reg.zx.org # 登录
5、构建企业级私有仓库
- 基于角色的访问控制(RBAC):可以为不同的用户和用户组分配不同的权限,增强了安全性和管理 的灵活性。
- 镜像复制:支持在不同的 Harbor 实例之间复制镜像,方便在多个数据中心或环境中分发镜像。
- 图形化用户界面(UI):提供了直观的 Web 界面,便于管理镜像仓库、项目、用户等。
- 审计日志:记录了对镜像仓库的各种操作,有助于追踪和审查活动。
- 垃圾回收:可以清理不再使用的镜像,节省存储空间。
(1)部署harbor
[root@local ~]# mkdir /data/certs -p
[root@local ~]# cp /root/certs/ /data/ -r
[root@local certs]# ls /data/certs
zx.org.crt zx.org.key
[root@local ~]# tar zxf harbor-offline-installer-v2.5.4.tgz
[root@local harbor]# cp harbor.yml.tmpl harbor.yml
[root@local harbor]# vim harbor.yml
hostname: reg.zx.org
certificate: /data/certs/zx.org.crt
private_key: /data/certs/zx.org.key
harbor_admin_password: 123
[root@local harbor]# ./install.sh --with-chartmuseum
#管理harbor的容器
[root@local harbor]# docker compose stop
[root@local harbor]# docker compose up -d
账号密码:admin 123
[root@docker-node1 harbor]# docker tag webserver:v1 reg.zx.org/zx/webserver:v1
[root@docker-node1 harbor]# systemctl restart docker
[root@docker-node1 harbor]# docker logout reg.zx.org
[root@docker-node1 harbor]# docker login reg.zx.org
Username: admin
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credential-stores
Login Succeeded
[root@docker-node1 harbor]# docker push reg.zx.org/zx/webserver:v1
The push refers to repository [reg.zx.org/zx/webserver]
f51abbf26a98: Pushed
6835249f577a: Pushed
24aacbf97031: Pushed
8451c71f8c1e: Pushed
2388d21e8e2b: Pushed
c048279a7d9f: Pushed
1a73b54f556b: Pushed
2a92d6ac9e4f: Pushed
bbb6cacb8c82: Pushed
ac805962e479: Pushed
af5aa97ebe6c: Pushed
4d049f83d9cf: Pushed
9ed498e122b2: Pushed
577c8ee06f39: Pushed
5342a2647e87: Pushed
v1: digest: sha256:4b28e604ba45d68b34d1e337241d1182e4e75a504e440d1284275be1c990cd89 size: 3445
[root@docker-node1 harbor]# vim /etc/docker/daemon.json
[root@docker-node1 harbor]# cat /etc/docker/daemon.json
{
"registry-mirrors": ["https://reg.zx.org"]
}
[root@docker-node1 harbor]# systemctl restart docker
[root@docker-node1 harbor]# docker info
(2)docker的webUI工具
[root@docker-node1 ~]# tar zxf 1panel-v1.10.13-lts-linux-amd64.tar.gz
[root@docker-node1 ~]# cd 1panel-v1.10.13-lts-linux-amd64/
[root@docker-node1 1panel-v1.10.13-lts-linux-amd64]# sh install.sh
五、Docker 网络
docker的镜像是令人称道的地方,但网络功能还是相对薄弱的部分
docker安装后会自动创建3种网络:bridge、host、none
[root@docker-node1 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
28b770857328 1panel-network bridge local
419fd92d3873 bridge bridge local
dc04306cd8fd harbor_harbor bridge local
1c490326af48 harbor_harbor-chartmuseum bridge local
e5317ef5d127 host host local
31b223297893 none null local
1、docker原生bridge网路
docker安装时会创建一个名为 docker0 的Linux bridge,新建的容器会自动桥接到这个接口
[root@docker-node1 ~]# ip link show type bridge
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
link/ether 02:42:6e:e0:17:a2 brd ff:ff:ff:ff:ff:ff
bridge模式下容器没有一个公有ip,只有宿主机可以直接访问,外部主机是不可见的。
容器通过宿主机的NAT规则后可以访问外网
# 还原默认网络配置
[root@docker-node1 ~]# cd 1panel-v1.10.13-lts-linux-amd64/
[root@docker-node1 1panel-v1.10.13-lts-linux-amd64]# 1pctl uninstall
卸载将会完全清除 1Panel 服务和数据目录,是否继续 [y/n] : y
================== 开始卸载 1Panel Linux 服务器运维管理面板 ==================
1) 停止 1Panel 服务进程...
2) 删除 1Panel 服务和数据目录...
3) 重新加载服务配置文件...
================================== 卸载完成 ==================================
[root@docker-node1 1panel-v1.10.13-lts-linux-amd64]# cd
[root@docker-node1 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
28b770857328 1panel-network bridge local
d8f5b73ad49a bridge bridge local
dc04306cd8fd harbor_harbor bridge local
1c490326af48 harbor_harbor-chartmuseum bridge local
e5317ef5d127 host host local
31b223297893 none null local
[root@docker-node1 ~]#
[root@docker-node1 ~]# docker network rm 1panel-network
[root@docker-node1 ~]# cd harbor/
[root@docker-node1 harbor]# docker compose down
[root@docker-node1 harbor]# iptables -nL # 查看防火墙规则
[root@docker-node1 ~]# iptables -t nat -nL
2、docker原生网络host
host网络模式需要在容器创建时指定 --network=host host
模式可以让容器共享宿主机网络栈,这样的好处是外部主机与容器直接通信,但是容器的网络缺少 隔离性
[root@docker-node1 ~]# docker run -it --name test --network host busybox
如果公用一个网络,那么所有的网络资源都是公用的,比如启动了nginx容器那么真实主机的80端口被占用,在启动第二个nginx容器就会失败
3、docker 原生网络none
none模式是指禁用网络功能,只有lo接口,在容器创建时使用 --network=none指定。
[root@docker-node1 ~]# docker run -it --name test --network none busybox
4、docker的自定义网络
自定义网络模式,docker提供了三种自定义网络驱动:
- bridge
- overlay
- macvlan
bridge驱动类似默认的bridge网络模式,但增加了一些新的功能
overlay和macvlan是用于创建跨主机网络
建议使用自定义的网络来控制哪些容器可以相互通信,还可以自动DNS解析容器名称到IP地址。
为什么要自定义桥接
docker引擎在分配ip时时根据容器启动顺序分配到,谁先启动谁用,是动态变更的
多容器互访用ip很显然不是很靠谱,那么多容器访问一般使用容器的名字访问更加稳定 docker原生网络是不支持dns解析的,自定义网络中内嵌了dns
注意:不同的自定义网络是不能通讯的
(1)自定义桥接网络
[root@docker-node1 ~]# docker network create my_net1
ff1dfd524682a9b144102384040ffa54ad18b391fc4e6655e238c5d3e66ed25d
[root@docker-node1 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
d8f5b73ad49a bridge bridge local
1c490326af48 harbor_harbor-chartmuseum bridge local
e5317ef5d127 host host local
ff1dfd524682 my_net1 bridge local
31b223297893 none null local
[root@docker-node1 ~]# docker run -it --name test --network bridge busybox
[root@docker-node1 ~]# docker run -it --name test0 --network bridge busybox
[root@docker-node1 ~]# docker run -it --name test1 --network my_net1 busybox
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:12:00:02
inet addr:172.18.0.2 Bcast:172.18.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:32 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:4716 (4.6 KiB) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
/ # ping -c 5 test
PING test (15.197.204.56): 56 data bytes
64 bytes from 15.197.204.56: seq=0 ttl=127 time=90.813 ms
64 bytes from 15.197.204.56: seq=1 ttl=127 time=90.716 ms
64 bytes from 15.197.204.56: seq=2 ttl=127 time=110.438 ms
64 bytes from 15.197.204.56: seq=3 ttl=127 time=93.006 ms
64 bytes from 15.197.204.56: seq=4 ttl=127 time=134.053 ms
--- test ping statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max = 90.716/103.805/134.053 ms
/ #
/ # ping -c 5 test0
PING test0 (15.197.204.56): 56 data bytes
64 bytes from 15.197.204.56: seq=0 ttl=127 time=122.564 ms
64 bytes from 15.197.204.56: seq=1 ttl=127 time=98.731 ms
64 bytes from 15.197.204.56: seq=2 ttl=127 time=106.459 ms
64 bytes from 15.197.204.56: seq=3 ttl=127 time=308.340 ms
64 bytes from 15.197.204.56: seq=4 ttl=127 time=105.651 ms
--- test0 ping statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max = 98.731/148.349/308.340 ms
# 桥接也支持自定义子网和网关
[root@docker-node1 ~]# docker network create my_net2 --subnet 192.168.0.0/24 --gateway 192.168.0.100
(2)如何让不同的自定义网络互通?
[root@docker-node1 ~]# docker network create mynet1 -d bridge
48671ec125476f49879ce9ae333e963c9de40a6d3ca1a9593bde4a68e39358db
[root@docker-node1 ~]#
[root@docker-node1 ~]# docker network create mynet2 -d bridge
c87f86f788792dc052419a7ae43babeb3ef8b531954d81b23b5f44ecbd8018da
[root@docker-node1 ~]#
[root@docker-node1 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
d8f5b73ad49a bridge bridge local
e5317ef5d127 host host local
48671ec12547 mynet1 bridge local
c87f86f78879 mynet2 bridge local
31b223297893 none null local
[root@docker-node1 ~]#
[root@docker-node1 ~]# iptables -nL
[root@docker-node1 ~]# docker run -it --name test --network mynet1 busybox
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:12:00:02
inet addr:172.18.0.2 Bcast:172.18.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:32 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:4716 (4.6 KiB) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
[root@docker-node1 ~]# docker run -it --name test1 --network mynet2 busybox
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:13:00:02
inet addr:172.19.0.2 Bcast:172.19.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:44 errors:0 dropped:0 overruns:0 frame:0
TX packets:7 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:6154 (6.0 KiB) TX bytes:452 (452.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:676 (676.0 B) TX bytes:676 (676.0 B)
[root@docker-node1 ~]# docker network connect mynet1 test1 在上面test1容器中加入网络eth1
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:13:00:02
inet addr:172.19.0.2 Bcast:172.19.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:47 errors:0 dropped:0 overruns:0 frame:0
TX packets:7 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:6364 (6.2 KiB) TX bytes:452 (452.0 B)
eth1 Link encap:Ethernet HWaddr 02:42:AC:12:00:02
inet addr:172.18.0.2 Bcast:172.18.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:17 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:2318 (2.2 KiB) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:676 (676.0 B) TX bytes:676 (676.0 B)
/ # ping -c 3 test
PING test (15.197.204.56): 56 data bytes
64 bytes from 15.197.204.56: seq=0 ttl=127 time=100.584 ms
64 bytes from 15.197.204.56: seq=1 ttl=127 time=131.775 ms
64 bytes from 15.197.204.56: seq=2 ttl=127 time=114.846 ms
--- test ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 100.584/115.735/131.775 ms
(3)joined容器网络
Joined容器一种较为特别的网络模式,在容器创建时使用--network=container:vm1指定。(vm1指定的是运行的容器名)
处于这个模式下的 Docker 容器会共享一个网络栈,这样两个容器之间可以使用localhost高效快速通信。
[root@docker-node1 ~]# docker run -it --name test --network mynet1 busybox
[root@docker-node1 ~]# docker run -it --name test1 --network container:test busybox
演示:利用容器部署phpmyadmin管理mysql
[root@docker-node1 ~]# docker load -i mysql-5.7.tar.gz
[root@docker-node1 ~]# docker load -i phpmyadmin-latest.tar.gz
#运行phpmysqladmin
[root@docker-node1 ~]# docker run -d --name mysqladmin --network mynet1 -e PMA_ARBITRARY=1 -p 80:80 phpmyadmin:latest
#运行数据库
[root@docker-node1 ~]# docker run -d --name mysql -e MYSQL_ROOT_PASSWORD='123' --network container:mysqladmin mysql:5.7
5、容器内外网的访问
(1)容器访问外网
在rhel7中,docker访问外网是通过iptables添加地址伪装策略来完成容器网文外网
在rhel7之后的版本中通过nftables添加地址伪装来访问外网
(2)外网访问docker容器
端口映射 -p 本机端口:容器端口来暴漏端口从而达到访问效果
docker-proxy和dnat在容器建立端口映射后都会开启,那个传输速录高走那个
#通过docker-proxy对数据包进行内转
[root@docker-node1 ~]# docker run -d --name webserver -p 80:80 nginx:1.23
[root@docker-node1 ~]# ps ax
……
11361 ? Sl 0:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 80 -container-ip 172.17.0.2 -cont
11367 ? Sl 0:00 /usr/bin/docker-proxy -proto tcp -host-ip :: -host-port 80 -container-ip 172.17.0.2 -container
11401 ? Sl 0:00 /usr/bin/containerd-shim-runc-v2 -namespace moby -id a57ab6ad12e5d22d66f4f195b4780081b6aeb7385
11423 ? Ss 0:00 nginx: master process nginx -g daemon off;
11463 ? S 0:00 nginx: worker process
11464 ? S 0:00 nginx: worker process
……
[root@docker-node1 ~]# iptables -t nat -nL # 查看策略
[root@docker-node1 ~]# docker inspect webserver
6、docker跨主机网络
在生产环境中,容器不可能都在同一个系统中,所以需要容器具备跨主机通信的能力
- 跨主机网络解决方案
- docker原生的overlay和macvlan
- 第三方的flannel、weave、calico
- 众多网络方案是如何与docker集成在一起的
- libnetwork docker容器网络库
- CNM (Container Network Model)这个模型对容器网络进行了抽象
(1)CNM(Container Network Model)
CNM分三类组件
- Sandbox:容器网络栈,包含容器接口、dns、路由表。(namespace)
- Endpoint:作用是将sandbox接入network (veth pair)
- Network:包含一组endpoint,同一network的endpoint可以通信
(2)macvlan网络方式实现跨主机通信
macvlan网络方式
- Linux kernel提供的一种网卡虚拟化技术。
- 无需Linux bridge,直接使用物理接口,性能极好
- 容器的接口直接与主机网卡连接,无需NAT或端口映射
- macvlan会独占主机网卡,但可以使用vlan子接口实现多macvlan网络
- vlan可以将物理二层网络划分为4094个逻辑网络,彼此隔离,vlan id取值为1~4094
macvlan网络间的隔离和连通
- macvlan网络在二层上是隔离的,所以不同macvlan网络的容器是不能通信的
- 可以在三层上通过网关将macvlan网络连通起来
- docker本身不做任何限制,像传统vlan网络那样管理即可
实现方法
1、在两台docker主机上各添加一块网卡,打开网卡混杂模式,第二块网卡 eth1 设置为仅主机模式
[root@docker-node2 ~]# ip link set eth1 promisc on
[root@docker-node2 ~]# ip link set up eth1
[root@docker-node2 ~]# ifconfig eth1
[root@docker-node1 ~]# ip link set eth1 promisc on
[root@docker-node1 ~]# ip link set up eth1
[root@docker-node1 ~]# ifconfig eth1
[root@docker-node2 ~]# docker load -i busybox-latest.tar.gz
2.添加macvlan网路
[root@docker-node1 ~]# docker network create -d macvlan --subnet 4.4.4.0/24 --gateway 4.4.4.4 -o parent=eth1 my-net1
[root@docker-node1 ~]# docker run -it --rm --name test --network my-net1 --ip 4.4.4.2 busybox
六、Docker 数据卷管理及优化
Docker 数据卷是一个可供容器使用的特殊目录,它绕过了容器的文件系统,直接将数据存储在宿主机上。
这样可以实现以下几个重要的目的:
- 数据持久化:即使容器被删除或重新创建,数据卷中的数据仍然存在,不会丢失。
- 数据共享:多个容器可以同时挂载同一个数据卷,实现数据的共享和交互。
- 独立于容器生命周期:数据卷的生命周期独立于容器,不受容器的启动、停止和删除的影响。
1、为什么要用数据卷
docker分层文件系统
- 性能差
- 生命周期与容器相同
docker数据卷
- mount到主机中,绕开分层文件系统
- 和主机磁盘性能相同,容器删除后依然保留
- 仅限本地磁盘,不能随容器迁移
docker提供了两种卷
- bind mount
- docker managed volume
/var/lib/docker/volumes
2、bind mount 数据卷
- 是将主机上的目录或文件mount到容器里。
- 使用直观高效,易于理解。
- 使用 -v 选项指定路径,格式 :-v 选项指定的路径,如果不存在,挂载时会自动创建
[root@docker-node1 ~]# docker run -it --rm --name test -v /zx:/data1:rw -v /etc/passwd:/data2/passwd busybox
/ # ls
bin data1 data2 dev etc home lib lib64 proc root sys tmp usr var
/ # ls data1
zxfile1 zxfile2 zxfile3 zxfile4 zxfile5
/ # touch data1/zxfile6
/ # ls data1
zxfile1 zxfile2 zxfile3 zxfile4 zxfile5 zxfile6
/ #
/ # ls /data2
passwd
3、docker managed 数据卷
- bind mount必须指定host文件系统路径,限制了移植性
- docker managed volume 不需要指定mount源,docker自动为容器创建数据卷目录
- 默认创建的数据卷目录都在 /var/lib/docker/volumes 中
- 如果挂载时指向容器内已有的目录,原有数据会被复制到volume中
[root@docker-node1 ~]# docker run -d --name mysql -e MYSQL_ROOT_PASSWORD='123' mysql:5.7
[root@docker-node1 ~]# docker inspect mysql
[root@docker-node1 ~]# docker volume prune # 清理未使用的 Docker 数据卷
[root@docker-node1 ~]# docker volume create mysqldate # 建立数据卷
[root@docker-node1 ~]# ll /var/lib/docker/volumes/mysqldate/_data/
total 0
[root@docker-node1 ~]# docker volume ls # 查看卷
DRIVER VOLUME NAME
local d7ce5a61e63a342c9668a4b4bb83b9bd109bf013c244e4302c5bbf9b7c9cb4b3
local mysqldate
[root@docker-node1 _data]# docker run -d --name mysql -e MYSQL_ROOT_PASSWORD='123' -v mysqldate:/var/lib/mysql -p 80:80 mysql:5.7
[root@docker-node1 ~]# docker inspect mysql
[root@docker-node1 ~]# cd /var/lib/docker/volumes/mysqldate/_data/
[root@docker-node1 _data]# ls
auto.cnf client-cert.pem ibdata1 ibtmp1 performance_schema server-cert.pem
ca-key.pem client-key.pem ib_logfile0 mysql private_key.pem server-key.pem
ca.pem ib_buffer_pool ib_logfile1 mysql.sock public_key.pem sys
[root@docker-node1 _data]#
[root@docker-node1 _data]# echo mysqldata > index.html
[root@docker-node1 _data]# curl 172.25.254.100
4、数据卷容器(Data Volume Container)
数据卷容器(Data Volume Container)是 Docker 中一种特殊的容器,主要用于方便地在多个容器之间共享数据卷。
(1)建立数据卷容器
[root@docker-node1 ~]# docker run -d --name datavol \
> -v /tmp/data1:/data1:rw \
> -v /tmp/data2:/data2:ro \
> -v /etc/resolv.conf:/etc/hosts busybox
(2)使用数据卷容器
[root@docker-node1 ~]# docker run -it --name test --rm --volumes-from datavol busybox
/ # ls
bin data1 data2 dev etc home lib lib64 proc root sys tmp usr var
/ # cat /etc/resolv.conf
# Generated by Docker Engine.
# This file can be edited; Docker Engine will not make further changes once it
# has been modified.
nameserver 114.114.114.114
search zx.org
# Based on host file: '/etc/resolv.conf' (legacy)
# Overrides: []
/ #
/ # touch data1/zxfile1
/ # touch data2/zxfile1
touch: data2/zxfile1: Read-only file system
5、bind mount 数据卷和docker managed 数据卷的对比
(1)相同点:
两者都是 host 文件系统中的某个路径
(2)不同点:
bind mount | docker managed volume | |
volume 位置 | 可任意指定 | /var/lib/docker/volumes/... |
对已有mount point影响 | 隐藏并替换为volume | 原有数据复制到volume |
是否支持单个位置 | 支持 | 不支持,只能是目录 |
权限控制 | 可设置为只读,默认为读写权限 | 无控制,均为读写权限 |
移植性 | 移植性弱,与host path绑定 | 移植性强,无需指定host目录 |
6、备份与迁移数据卷
(1)备份数据卷
#建立容器并指定使用卷到要备份的容器
[root@docker-node1 ~]# docker run -d --name datavol -v /tmp/data1:/data1:rw -v /tmp/data2:/data2:ro -v /etc/resolv.conf:/etc/hosts busybox
#把当前目录挂在到容器中用于和容器交互保存要备份的容器,备份数据到本地
[root@docker-node1 ~]# docker run --volumes-from datavol \
> -v `pwd`:/backup busybox \
> tar zcf /backup/data1.tar.gz /data1
(2)数据恢复
#数据恢复
[root@docker-node1 ~]# docker run -it --name test -v zxvol1:/data1 -v `pwd`:/backup busybox /bin/sh -c "tar zxf /backup/data1.tar.gz;/bin/sh"
/ # ls
backup data1 etc lib proc sys usr
bin dev home lib64 root tmp var
/ # cd data1/
/data1 # ls
zxfile1
/data1 #
七、Docker 的安全优化
Docker容器的安全性,很大程度上依赖于Linux系统自身
评估Docker的安全性时,主要考虑以下几个方面:
- Linux内核的命名空间机制提供的容器隔离安全
- Linux控制组机制对容器资源的控制能力安全
- Linux内核的能力机制所带来的操作权限安全
- Docker程序(特别是服务端)本身的抗攻击性
- 其他安全增强机制对容器安全性的影响
#在rhel9中默认使用cgroup-v2 但是cgroup-v2中不利于观察docker的资源限制情况,所以推荐使用cgroup-v1
[root@docker-node1 cgroup]# grubby --update-kernel=/boot/vmlinuz-$(uname -r) \
> --args="systemd.unified_cgroup_hierarchy=0 \
> systemd.legacy_systemd_cgroup_controller"
或者
sudo grubby --update-kernel=ALL --args="systemd.unified_cgroup_hierarchy=1"
命名空间隔离的安全
- 当docker run启动一个容器时,Docker将在后台为容器创建一个独立的命名空间。命名空间提供了 最基础也最直接的隔离。
- 与虚拟机方式相比,通过Linux namespace来实现的隔离不是那么彻底。
- 容器只是运行在宿主机上的一种特殊的进程,那么多个容器之间使用的就还是同一个宿主机的操作 系统内核。
- 在 Linux 内核中,有很多资源和对象是不能被 Namespace 化的,比如:磁盘等等
控制组资源控制的安全
- 当docker run启动一个容器时,Docker将在后台为容器创建一个独立的控制组策略集合。
- Linux Cgroups提供了很多有用的特性,确保各容器可以公平地分享主机的内存、CPU、磁盘IO等资源。
- 确保当发生在容器内的资源压力不会影响到本地主机系统和其他容器,它在防止拒绝服务攻击 (DDoS)方面必不可少
#内存资源默认没有被隔离
[root@docker-node1 ~]# docker run -it --name test busybox
/ # free -m
total used free shared buff/cache available
Mem: 1751 519 199 10 1033 1054
Swap: 2072 16 2056
/ # exit
[root@docker-node1 ~]# free -m
total used free shared buff/cache available
Mem: 1750 651 243 10 1032 1098
Swap: 2071 15 2056
内核能力机制
- 能力机制(Capability)是Linux内核一个强大的特性,可以提供细粒度的权限访问控制。
- 大部分情况下,容器并不需要“真正的”root权限,容器只需要少数的能力即可。
- 默认情况下,Docker采用“白名单”机制,禁用“必需功能”之外的其他权限。
Docker服务端防护
- 使用Docker容器的核心是Docker服务端,确保只有可信的用户才能访问到Docker服务。
- 将容器的root用户映射到本地主机上的非root用户,减轻容器和主机之间因权限提升而引起的安全 问题。
- 允许Docker 服务端在非root权限下运行,利用安全可靠的子进程来代理执行需要特权权限的操作。 这些子进程只允许在特定范围内进行操作。
#默认docker是用root用户控制资源的
[root@docker-node1 ~]# ls -ld /var/lib/docker/
drwx--x--- 12 root root 171 Aug 30 20:39 /var/lib/docker/
1、Docker的资源限制
Linux Cgroups 的全称是 Linux Control Group。
- 是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等。
- 对进程进行优先级设置、审计,以及将进程挂起和恢复等操作。
Linux Cgroups 给用户暴露出来的操作接口是文件系统
- 它以文件和目录的方式组织在操作系统的 /sys/fs/cgroup 路径下。
- 执行此命令查看:mount -t cgroup
- 在 /sys/fs/cgroup 下面有很多诸如 cpuset、cpu、 memory 这样的子目录,也叫子系统。
- 在每个子系统下面,为每个容器创建一个控制组(即创建一个新目录)。
- 控制组下面的资源文件里填上什么值,就靠用户执行 docker run 时的参数指定。
[root@docker-node1 ~]# mount -t cgroup
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,name=systemd)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/misc type cgroup (rw,nosuid,nodev,noexec,relatime,misc)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
[root@docker-node1 ~]#
(1)限制CPU使用
[root@docker-node1 ~]# docker load -i ubuntu-latest.tar.gz
#设置 CPU 周期的长度,单位为微秒(通常为100000,即 100 毫秒)
#设置容器在一个周期内可以使用的 CPU 时间,单位也是微秒。
[root@docker-node1 ~]# docker run -it --name test1 --rm --cpu-period 10000 --cpu-quota 20000 ubuntu
root@38f21bdd925b:/# dd if=/dev/zero of=/dev/null &
[1] 9
root@38f21bdd925b:/# top
#在cgroup中查看docker的资源限制
[root@docker-node1 ~]# cat /sys/fs/cgroup/system.slice/docker-38f21bdd925b8a1b269a085168a579c43c37e80b0501d8473b7a5c5dc1a9e53e.scope/cpu.max
20000 10000
(2)限制CPU的优先级
#关闭cpu的核心,当cpu都不空闲下才会出现争抢的情况,为了实验效果关闭一个cpu核心
[root@docker-node1 ~]# echo 0 > /sys/devices/system/cpu/cpu1/online # 限制为单核
[root@docker-node1 ~]# cat /proc/cpuinfo
# 单核下
[root@docker-node1 ~]# docker run -it --rm --cpu-shares 100 ubuntu
root@dea27188a3ff:/# dd if=/dev/zero of=/dev/null &
# 双核下
[root@docker-node2 ~]# docker load -i ubuntu-latest.tar.gz
f36fd4bb7334: Loading layer 80.56MB/80.56MB
Loaded image: ubuntu:latest
[root@docker-node2 ~]#
[root@docker-node2 ~]# docker run -it --rm --cpu-shares 100 ubuntu
root@0569400ae98d:/# dd if=/dev/zero of=/dev/null &
[1] 9
root@0569400ae98d:/# top
在单核下明显看到CPU的使用被限制到,双核下未被限制住CPU的使用,但CPU的优先级两者皆能明显看到效果——在首行
(3)限制内存使用
[root@docker-node1 ~]# docker run --name test -it --memory 200M --memory-swap 200M ubuntu
[root@docker-node1 ~]# cd /sys/fs/cgroup/memory/docker/
[root@docker-node1 docker]# cd b2e88d44be7d526be64f49f0d90189bacb813b4aed2dfb5b1aba8368ae48ea0c/
[root@docker-node1 b2e88d44be7d526be64f49f0d90189bacb813b4aed2dfb5b1aba8368ae48ea0c]# cat memory.limit_in_bytes
209715200
[root@docker-node1 b2e88d44be7d526be64f49f0d90189bacb813b4aed2dfb5b1aba8368ae48ea0c]# cat memory.memsw.limit_in_bytes
209715200
法一
测试容器内存限制,在容器中我们测试内存限制效果不是很明显,可以利用工具模拟容器在内存中写入数据,在系统中/dev/shm这个目录被挂在到内存中
cgexec -g memory:doceker/容器id -g表示使用指定控制器类型
[root@docker-node1 ~]# dnf install libcgroup-0.41-19.el8.x86_64.rpm -y
[root@docker-node1 ~]# dnf install libcgroup-tools-0.41-19.el8.x86_64.rpm -y
[root@docker-node1 ~]# docker run --name test -it --memory 200M --memory-swap 200M ubuntu
[root@docker-node1 docker]# cgexec -g memory:docker/8bc9895a1f6fd846293945c23e470c9ff4c2dd3c74b17ce2b14f33a8e6a7ebdd/ dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 0.111329 s, 942 MB/s
[root@docker-node1 docker]#
[root@docker-node1 docker]# cgexec -g memory:docker/8bc9895a1f6fd846293945c23e470c9ff4c2dd3c74b17ce2b14f33a8e6a7ebdd/ dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=150
150+0 records in
150+0 records out
157286400 bytes (157 MB, 150 MiB) copied, 0.116302 s, 1.4 GB/s
[root@docker-node1 docker]# cgexec -g memory:docker/8bc9895a1f6fd846293945c23e470c9ff4c2dd3c74b17ce2b14f33a8e6a7ebdd/ dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=200
Killed
法二:自建控制器
[root@docker-node1 ~]# cd /sys/fs/cgroup/memory/
[root@docker-node1 memory]#
[root@docker-node1 memory]# ls
cgroup.clone_children memory.kmem.tcp.limit_in_bytes memory.soft_limit_in_bytes
cgroup.event_control memory.kmem.tcp.max_usage_in_bytes memory.stat
cgroup.procs memory.kmem.tcp.usage_in_bytes memory.swappiness
cgroup.sane_behavior memory.kmem.usage_in_bytes memory.usage_in_bytes
dev-hugepages.mount memory.limit_in_bytes memory.use_hierarchy
dev-mqueue.mount memory.max_usage_in_bytes notify_on_release
docker memory.memsw.failcnt release_agent
memory.failcnt memory.memsw.limit_in_bytes sys-fs-fuse-connections.mount
memory.force_empty memory.memsw.max_usage_in_bytes sys-kernel-config.mount
memory.kmem.failcnt memory.memsw.usage_in_bytes sys-kernel-debug.mount
memory.kmem.limit_in_bytes memory.move_charge_at_immigrate sys-kernel-tracing.mount
memory.kmem.max_usage_in_bytes memory.numa_stat system.slice
memory.kmem.slabinfo memory.oom_control tasks
memory.kmem.tcp.failcnt memory.pressure_level user.slice
[root@docker-node1 memory]# mkdir x1
[root@docker-node1 memory]# cd x1/
[root@docker-node1 x1]# ls
cgroup.clone_children memory.kmem.tcp.max_usage_in_bytes memory.oom_control
cgroup.event_control memory.kmem.tcp.usage_in_bytes memory.pressure_level
cgroup.procs memory.kmem.usage_in_bytes memory.soft_limit_in_bytes
memory.failcnt memory.limit_in_bytes memory.stat
memory.force_empty memory.max_usage_in_bytes memory.swappiness
memory.kmem.failcnt memory.memsw.failcnt memory.usage_in_bytes
memory.kmem.limit_in_bytes memory.memsw.limit_in_bytes memory.use_hierarchy
memory.kmem.max_usage_in_bytes memory.memsw.max_usage_in_bytes notify_on_release
memory.kmem.slabinfo memory.memsw.usage_in_bytes tasks
memory.kmem.tcp.failcnt memory.move_charge_at_immigrate
memory.kmem.tcp.limit_in_bytes memory.numa_stat
#内存可用大小限制
[root@docker-node1 x1]# echo 209715200 > /sys/fs/cgroup/memory/x1/memory.limit_in_bytes
#此控制器被那个进程调用
[root@docker-node1 x1]# cat /sys/fs/cgroup/memory/x1/tasks
[root@docker-node1 x1]# cgexec -g memory:x1 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 0.0869935 s, 1.2 GB/s
[root@docker-node1 x1]# free -m
total used free shared buff/cache available
Mem: 1750 685 451 107 874 1065
Swap: 2071 0 2071
[root@docker-node1 x1]# cgexec -g memory:x1 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=300
300+0 records in
300+0 records out
314572800 bytes (315 MB, 300 MiB) copied, 0.771034 s, 408 MB/s
[root@docker-node1 x1]# free -m
total used free shared buff/cache available
Mem: 1750 783 353 184 953 967
Swap: 2071 122 1949
#内存溢出部分被写入swap交换分区
[root@docker-node1 ~]# rm -fr /dev/shm/bigfile
[root@docker-node1 ~]# echo 209715200 > /sys/fs/cgroup/memory/x1/memory.memsw.limit_in_bytes #内存+swap控制
[root@docker-node1 ~]# cgexec -g memory:x1 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=200
Killed
[root@docker-node1 ~]# cgexec -g memory:x1 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=199
Killed
[root@docker-node1 ~]# cgexec -g memory:x1 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=190
190+0 records in
190+0 records out
199229440 bytes (199 MB, 190 MiB) copied, 0.133858 s, 1.5 GB/s
(4)限制docker的磁盘io
[root@docker-node1 ~]# docker run -it --rm --device-write-bps /dev/nvme0n1:30M ubuntu
root@d61e5f1cc529:/# dd if=/dev/zero of=bigfile
^C19831485+0 records in
19831485+0 records out
10153720320 bytes (10 GB, 9.5 GiB) copied, 59.5736 s, 170 MB/s
root@d61e5f1cc529:/# dd if=/dev/zero of=bigfile bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 0.101623 s, 1.0 GB/s
root@d61e5f1cc529:/#
root@d61e5f1cc529:/# dd if=/dev/zero of=bigfile bs=1M count=100 oflag=direct
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 3.33883 s, 31.4 MB/s
2、Docker的安全加固
(1)Docker默认隔离性
在系统中运行容器,我们会发现资源并没有完全隔离开
虽然限制了容器的内容使用情况,但是查看到的信息依然是系统中内存的使用信息,并没有隔离开
(2)解决Docker的默认隔离性
LXCFS 是一个为 LXC(Linux Containers)容器提供增强文件系统功能的工具。
主要功能
1. 资源可见性: LXCFS 可以使容器内的进程看到准确的 CPU、内存和磁盘 I/O 等资源使用信息。在没有 LXCFS 时,容器内看到的资源信息可能不准确,这会影响到在容器内运行的应用程序对资源的评估和 管理。
2. 性能监控: 方便对容器内的资源使用情况进行监控和性能分析。通过提供准确的资源信息,管理员和开发 人员可以更好地了解容器化应用的性能瓶颈,并进行相应的优化。
# 安装lxcfs
[root@docker-node1 ~]# mkdir lxc
[root@docker-node1 ~]# cd lxc
[root@docker-node1 lxc]# ls
lxcfs-5.0.4-1.el9.x86_64.rpm lxc-libs-4.0.12-1.el9.x86_64.rpm lxc-templates-4.0.12-1.el9.x86_64.rpm
[root@docker-node1 lxc]# dnf install *.rpm -y
# 运行lxcfs并解决容器隔离性
[root@docker-node1 ~]# lxcfs /var/lib/lxcfs & # 打入后台运行
[1] 6082
[root@docker-node1 ~]# ps ax
……
6082 pts/0 Sl 0:00 lxcfs /var/lib/lxcfs
……
[root@docker-node1 ~]# cd /var/lib/lxcfs/
[root@docker-node1 lxcfs]# ls
cgroup proc sys
[root@docker-node1 ~]# docker run -it -m 256m --name test \
> -v /var/lib/lxcfs/proc/cpuinfo:/proc/cpuinfo:rw \
> -v /var/lib/lxcfs/proc/diskstats:/proc/diskstats:rw \
> -v /var/lib/lxcfs/proc/meminfo:/proc/meminfo:rw \
> -v /var/lib/lxcfs/proc/stat:/proc/stat:rw \
> -v /var/lib/lxcfs/proc/swaps:/proc/swaps:rw \
> -v /var/lib/lxcfs/proc/uptime:/proc/uptime:rw \
> ubuntu
(3)容器特权
在容器中默认情况下即使我是容器的超级用户也无法修改某些系统设定,比如网络
[root@docker-node1 ~]#
[root@docker-node1 ~]# docker run --rm -it busybox
/ #
/ #
/ # whoami
root
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
33: eth0@if34: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
/ #
/ # ip addr add 192.168.0.100/24 dev eth0
ip: RTNETLINK answers: Operation not permitted # 不允许添加
这是因为容器使用的很多资源都是和系统真实主机公用的,如果允许容器修改这些重要资源,系统的稳定性会变的非常差
但是由于某些需要求,容器需要控制一些默认控制不了的资源,如何解决此问题,这时我们就要设置容器特权
[root@docker-node1 ~]# docker run --rm -it --privileged busybox
(4)容器特权的白名单
--privileged=true 的权限非常大,接近于宿主机的权限,为了防止用户的滥用,需要增加限制,只提供给容器必须的权限。此时Docker 提供了权限白名单的机制,使用--cap-add添加必要的权限
#限制容器对网络有root权限
[root@docker-node1 ~]# docker run --rm -it --cap-add NET_ADMIN busybox
八、容器编排工具Docker Compose
1、Docker Compose 概述
Docker Compose 是一个用于定义和运行多容器 Docker 应用程序的工具。 其是官方的一个开源项目,托管到github上
主要功能
1. 定义服务
使用 YAML 格式的配置文件来定义一组相关的容器服务。每个服务可以指定镜像、端口映射、 环境变量、存储卷等参数。
例如,可以在配置文件中定义一个 Web 服务和一个数据库服务,以及它们之间的连接关系。
2. 一键启动和停止
通过一个简单的命令,可以启动或停止整个应用程序所包含的所有容器。这大大简化了多容器应用的部署和管理过程。 例如,使用 docker-compose up 命令可以启动配置文件中定义的所有服务,使用 dockercompose down 命令可以停止并删除这些服务。
3. 服务编排
可以定义容器之间的依赖关系,确保服务按照正确的顺序启动和停止。例如,可以指定数据库服务必须在 Web 服务之前启动。
支持网络配置,使不同服务的容器可以相互通信。可以定义一个自定义的网络,将所有相关的容器连接到这个网络上。
4. 环境变量管理
可以在配置文件中定义环境变量,并在容器启动时传递给容器。这使得在不同环境(如开发、 测试和生产环境)中使用不同的配置变得更加容易。 例如,可以定义一个数据库连接字符串的环境变量,在不同环境中可以设置不同的值。
Docker Compose 中的管理层
1. 服务 (service) 一个应用的容器,实际上可以包括若干运行相同镜像的容器实例
2. 项目 (project) 由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义
3. 容器(container)容器是服务的具体实例,每个服务可以有一个或多个容器。容器是基于服务定义的镜像创建的运行实例
工作原理
- 读取配置文件: Docker Compose 读取 YAML 配置文件,解析其中定义的服务和参数。
- 创建容器: 根据配置文件中的定义,Docker Compose 调用 Docker 引擎创建相应的容器。它会下载所需 的镜像(如果本地没有),并设置容器的各种参数。
- 管理容器生命周期: Docker Compose 监控容器的状态,并在需要时启动、停止、重启容器。 它还可以处理容器的故障恢复,例如自动重启失败的容器。
2、Docker Compose 的常用命令参数
[root@docker-node1 ~]# vim ~/.vimrc
[root@docker-node1 ~]# cat ~/.vimrc
set ts=2 sw=2 ai et
[root@docker-node1 ~]# mkdir test
[root@docker-node1 test]# vim docker-compose.yml
[root@docker-node1 test]# cat docker-compose.yml
services:
web:
image: nginx:latest
ports:
- "80:80"
testnode:
image: busybox:latest
command: ["/bin/sh","-c","sleep 100000"]
(1)服务管理
docker compose up
- 启动配置文件中定义的所有服务。
- 可以使用 -d 参数在后台启动服务。
- 可以使用-f 来指定yml文件
[root@docker-node1 test]# docker compose up -d
[+] Running 3/3
✔ Network test_default Created 0.3s
✔ Container test-web-1 Started 1.4s
✔ Container test-testnode-1 Started 1.4s
[root@docker-node1 test]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bcbe4e548443 busybox:latest "/bin/sh -c 'sleep 1…" About a minute ago Up About a minute test-testnode-1
9fa44d75189b nginx:latest "/docker-entrypoint.…" About a minute ago Up About a minute 0.0.0.0:80->80/tcp, :::80->80/tcp test-web-1
[root@docker-node1 ~]# docker compose -f test/docker-compose.yml up -d
[+] Running 2/2
✔ Container test-web-1 Started 0.9s
✔ Container test-testnode-1 Started 0.7s
[root@docker-node1 ~]#
[root@docker-node1 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8cfe11057ac7 nginx:latest "/docker-entrypoint.…" 9 seconds ago Up 8 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp test-web-1
280c8288c6ac busybox:latest "/bin/sh -c 'sleep 1…" 9 seconds ago Up 8 seconds test-testnode-1
docker compose down
停止并删除配置文件中定义的所有服务以及相关的网络和存储卷。
[root@docker-node1 test]# docker compose down
[+] Running 3/3
✔ Container test-testnode-1 Removed 10.3s
✔ Container test-web-1 Removed 0.2s
✔ Network test_default Removed 0.2s
docker compose start
启动已经存在的服务,但不会创建新的服务。
[root@docker-node1 test]# docker compose start
docker compose stop
[root@docker-node1 test]# docker compose stop
docker compose restart
[root@docker-node1 test]# docker ps -a
(2)服务状态查看
docker compose ps
列出正在运行的服务以及它们的状态,包括容器 ID、名称、端口映射等信息。
[root@docker-node1 test]# docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
test-testnode-1 busybox:latest "/bin/sh -c 'sleep 1…" testnode 5 minutes ago Up About a minute
test-web-1 nginx:latest "/docker-entrypoint.…" web 5 minutes ago Up About a minute 0.0.0.0:80->80/tcp, :::80->80/tcp
docker compose logs
查看服务的日志输出。可以指定服务名称来查看特定服务的日志。
[root@docker-node1 test]# docker compose logs web
(3)构建和重新构建服务
docker-compose build
构建配置文件中定义的服务的镜像。可以指定服务名称来只构建特定的服务。
[root@docker-node1 ~]# mkdir -p /root/docker
[root@docker-node1 ~]# cd /root/docker/
[root@docker-node1 docker]# vim Dockerfile
[root@docker-node1 docker]# vim zx
[root@docker-node1 docker]# cat Dockerfile
FROM busybox:latest
RUN touch /zxfile1
[root@docker-node1 docker]# cat zx
FROM busybox:latest
RUN touch /zxfile2
[root@docker-node1 ~]# cd /root/test/
[root@docker-node1 test]# ls
docker-compose.yml
[root@docker-node1 test]# vim docker-compose.yml
[root@docker-node1 test]# cat docker-compose.yml
services:
test1:
image: test1
build:
context: /root/docker
dockerfile: Dockerfile
command: ["/bin/sh","-c","sleep 3000"]
restart: always
container_name: zx1
test2:
image: test2
build:
context: /root/docker
dockerfile: zx
command: ["/bin/sh","-c","sleep 3000"]
restart: always
container_name: zx2
[root@docker-node1 test]# docker compose up -d #构建services中的所有
[root@docker-node1 test]# docker compose build test1 #构建services中的test1
docker compose up --build
启动服务并在启动前重新构建镜像
[root@docker-node1 test]# docker compose up #会去仓库拉去镜像
[root@docker-node1 test]# docker compose up --build #会先构建镜像后启动容器
(4)其他操作
docker-compose exec
在正在运行的服务容器中执行命令
[root@docker-node1 test]# docker compose up -d
[root@docker-node1 test]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
776e0e93f6b7 test1 "/bin/sh -c 'sleep 3…" 4 minutes ago Up 39 seconds zx1
e10db596eebf test2 "/bin/sh -c 'sleep 3…" 4 minutes ago Up 39 seconds zx2
[root@docker-node1 test]# docker compose exec test1 sh
docker-compose pull
拉取配置文件中定义的服务所使用的镜像。
[root@docker-node1 test]# docker compose pull # 不运行,只拉取镜像
docker-compose config
[root@docker-node1 test]# docker compose config
[root@docker-node1 test]# docker compose config -q
3、Docker Compose 的yml文件
Docker Compose 的 YAML 文件用于定义和配置多容器应用程序的各个服务。
以下是一个基本的 Docker Compose YAML 文件结构及内容解释:
(1)服务
服务名称(service1_name/service2_name 等)
每个服务在配置文件中都有一个唯一的名称,用于在命令行和其他部分引用该服务
services:
web:
# 服务1的配置
mysql:
# 服务2的配置
镜像(image)
指定服务所使用的 Docker 镜像名称和标签。
例如, image: nginx:latest 表示使用 nginx 镜像的最新版本
services:
web:
images:nginx
mysql:
images:mysql:5.7
端口映射
将容器内部的端口映射到主机的端口,以便外部可以访问容器内的服务。例如, - "8080:80" 表示将主机的 8080 端口映射到容器内部的 80 端口。
[root@docker-node1 test]# cat docker-compose.yml
services:
test1:
image: test1
build:
context: /root/docker
dockerfile: Dockerfile
command: ["/bin/sh","-c","sleep 3000"]
restart: always
container_name: zx1
expose:
- 1234
[root@docker-node1 test]# cat docker-compose.yml
services:
test1:
image: nginx
container_name: webserver
ports:
- "80:8080"
环境变量(environment)
为容器设置环境变量,可以在容器内部的应用程序中使用。
例如, VAR1: value1 设置环境变 量 VAR1 的值为 value1
[root@docker-node1 test]# vim docker-compose.yml
[root@docker-node1 test]# cat docker-compose.yml
services:
test1:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: 123
[root@docker-node1 test]# docker compose up -d
[+] Running 2/2
? Network test_default Created 0.2s
? Container test-test1-1 Started 1.0s
[root@docker-node1 test]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ff2ece17fbba mysql:5.7 "docker-entrypoint.s…" 8 seconds ago Up 7 seconds 3306/tcp, 33060/tcp test-test1-1
[root@docker-node1 test]#
[root@docker-node1 test]# docker inspect test-test1-1
存储卷(volumes)
将主机上的目录或文件挂载到容器中,以实现数据持久化或共享。
例如, - /host/data:/container/data 将主机上的 /host/data 目录挂载到容器内的 /container/data 路径
[root@docker-node1 test]# vim docker-compose.yml
[root@docker-node1 test]# docker compose up -d
[+] Running 2/2
✔ Network test_default Created 0.3s
✔ Container test-test1-1 Started 0.8s
[root@docker-node1 test]# cat docker-compose.yml
services:
test1:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: 123
volumes:
- /opt/mysql_data:/var/lib/mysql
[root@docker-node1 test]# docker inspect test-test1-1
网络(networks)
将服务连接到特定的网络,以便不同服务的容器可以相互通信
root@docker-node1 ~]# cd test/
[root@docker-node1 test]# docker compose down
[+] Running 2/2
? Container test-test1-1 Removed 2.2s
? Network test_default Removed 0.2s
[root@docker-node1 test]#
[root@docker-node1 test]# vim docker-compose.yml
[root@docker-node1 test]# docker compose up -d
[+] Running 2/2
? Network test_default Created 0.3s
? Container zx Started 0.7s
[root@docker-node1 test]# docker network ls
NETWORK ID NAME DRIVER SCOPE
2ee0d242a5d0 bridge bridge local
e5317ef5d127 host host local
31b223297893 none null local
93e724548860 test_default bridge local
[root@docker-node1 test]# cat docker-compose.yml
services:
test1:
image: busybox:latest
container_name: zx
command: ["/bin/sh","-c","sleep100000"]
#使用本机自带bridge网络
[root@docker-node1 test]# vim docker-compose.yml
[root@docker-node1 test]# cat docker-compose.yml
services:
test1:
image: busybox:latest
container_name: zx
command: ["/bin/sh","-c","sleep100000"]
network_mode: bridge
[root@docker-node1 test]# docker compose up -d
[+] Running 1/1
✔ Container zx Started 0.6s
[root@docker-node1 test]# docker network ls
NETWORK ID NAME DRIVER SCOPE
2ee0d242a5d0 bridge bridge local
e5317ef5d127 host host local
31b223297893 none null local
[root@docker-node1 test]# vim docker-compose.yml
[root@docker-node1 test]# cat docker-compose.yml
services:
test1:
image: busybox:latest
container_name: zx
command: ["/bin/sh","-c","sleep100000"]
network_mode: none
[root@docker-node1 test]# docker compose up -d
[+] Running 1/1
✔ Container zx Started 0.5s
[root@docker-node1 test]# docker network ls
NETWORK ID NAME DRIVER SCOPE
2ee0d242a5d0 bridge bridge local
e5317ef5d127 host host local
31b223297893 none null local
# 自建网络
[root@docker-node1 test]# vim docker-compose.yml
[root@docker-node1 test]# docker compose up -d
[+] Running 3/3
✔ Network test_mynet1 Created 0.3s
✔ Network test_mynet2 Created 0.2s
✔ Container zx Started 0.7s
[root@docker-node1 test]# docker network ls
NETWORK ID NAME DRIVER SCOPE
2ee0d242a5d0 bridge bridge local
e5317ef5d127 host host local
31b223297893 none null local
97033aa95bfc test_mynet1 bridge local
06cbdbd6a62f test_mynet2 bridge local
[root@docker-node1 test]# cat docker-compose.yml
services:
test1:
image: busybox:latest
container_name: zx
command: ["/bin/sh","-c","sleep100000"]
networks:
- mynet1
- mynet2
networks:
mynet1:
driver: bridge
mynet2:
driver: bridge
命令(command)
覆盖容器启动时默认执行的命令。例如, command: python app.py 指定容器启动时运行 python app.py 命令
[root@docker-node1 test]# cat docker-compose.yml
services:
test1:
image: busybox:latest
container_name: zx
command: ["/bin/sh","-c","sleep100000"]
(2)网络(networks)
- 定义 Docker Compose 应用程序中使用的网络。可以自定义网络名称和驱动程序等属性。
- 默认情况下docker compose 在执行时会自动建立网路
#不建立新的网络而使用外部资源
[root@docker-node1 test]# docker compose down
[+] Running 3/3
✔ Container zx Removed 0.0s
✔ Network test_mynet1 Removed 0.2s
✔ Network test_mynet2 Removed 0.4s
[root@docker-node1 test]#
[root@docker-node1 test]# vim docker-compose.yml
[root@docker-node1 test]# docker compose up -d
[+] Running 1/1
✔ Container test Started 0.6s
[root@docker-node1 test]# docker network ls
NETWORK ID NAME DRIVER SCOPE
2ee0d242a5d0 bridge bridge local
e5317ef5d127 host host local
31b223297893 none null local
[root@docker-node1 test]# cat docker-compose.yml
services:
test:
image: busybox:latest
container_name: test
command: ["/bin/sh","-c","sleep 10000"]
network_mode: default
networks:
default:
external: true #不建立新的网络而使用外部资源
name: bridge #指定外部资源网络名字
[root@docker-node1 test]# docker compose down
[+] Running 1/1
? Container test Removed 10.3s
[root@docker-node1 test]# vim docker-compose.yml
[root@docker-node1 test]# docker compose up -d
[+] Running 3/3
? Network test_mynet1 Created 0.3s
? Container test2 Started 0.8s
? Container test Started 0.8s
[root@docker-node1 test]# cat docker-compose.yml
services:
test:
image: busybox:latest
container_name: test
command: ["/bin/sh","-c","sleep 10000"]
network_mode: default
test2:
image: busybox:latest
container_name: test2
command: ["/bin/sh","-c","sleep 10000"]
networks:
- mynet1
networks:
default:
external: true
name: bridge
mynet1:
driver: bridge
[root@docker-node1 test]# docker network ls
NETWORK ID NAME DRIVER SCOPE
2ee0d242a5d0 bridge bridge local
e5317ef5d127 host host local
31b223297893 none null local
334b5038cf75 test_mynet1 bridge local
[root@docker-node1 test]# vim docker-compose.yml
[root@docker-node1 test]# docker compose up -d
[+] Running 3/3
? Network test_mynet2 Created
? Container test2 Started
? Container test Started
[root@docker-node1 test]# docker network ls
NETWORK ID NAME DRIVER SCOPE
2ee0d242a5d0 bridge bridge local
e5317ef5d127 host host local
31b223297893 none null local
a7fa4f01b875 test_mynet1 bridge local
8b6e852c9552 test_mynet2 bridge local
[root@docker-node1 test]# cat docker-compose.yml
services:
test:
image: busybox:latest
container_name: test
command: ["/bin/sh","-c","sleep 10000"]
network_mode: default
test2:
image: busybox:latest
container_name: test2
command: ["/bin/sh","-c","sleep 10000"]
networks:
- mynet1
- mynet2
networks:
default:
external: true
name: bridge
mynet1:
driver: bridge
mynet2:
ipam:
driver: default
config:
- subnet: 172.26.0.0/24
gateway: 172.26.0.254
[root@docker-node1 ~]# docker exec -it test2 sh
/ # ifconfig
/ # route -n
3、存储卷
定义 Docker Compose 应用程序中使用的存储卷。可以自定义卷名称和存储位置等属性。
[root@docker-node1 test]# vim docker-compose.yml
[root@docker-node1 test]# docker compose up -d
[+] Running 3/3
✔ Volume "zx" Created 0.0s
✔ Container test Runni... 0.0s
✔ Container test2 Star... 11.0s
[root@docker-node1 test]# docker inspect test2
[root@docker-node1 test]# docker exec -it test2 sh
/ # ls
bin dev home lib64 root tmp var
data etc lib proc sys usr
/ # cd data/
/data # touch file
/data # exit
[root@docker-node1 test]# docker compose down
[root@docker-node1 ~]# cd /var/lib/docker/
[root@docker-node1 docker]# cd volumes/
[root@docker-node1 volumes]# cd zx/
[root@docker-node1 zx]# ls
_data
[root@docker-node1 zx]# cd _data/
[root@docker-node1 _data]# ls
file
4、企业示例
利用容器编排完成haproxy和nginx负载均衡架构实施
[root@docker-node1 ~]# cd test/
[root@docker-node1 test]# mkdir -p /var/lib/docker/volumes/conf
[root@docker-node1 ~]# dnf install haproxy -y --downloadonly --downloaddir=/mnt
[root@docker-node1 ~]# cd /mnt
[root@docker-node1 mnt]# rpm2cpio haproxy-2.4.17-6.el9.x86_64.rpm | cpio -id
13421 blocks
[root@docker-node1 mnt]# cd /etc
[root@docker-node1 etc]# ls
haproxy logrotate.d sysconfig
[root@docker-node1 etc]# cd haproxy/
[root@docker-node1 haproxy]# ls
conf.d haproxy.cfg
[root@docker-node1 haproxy]# cp haproxy.cfg /var/lib/docker/volumes/conf/
[root@docker-node1 haproxy]# cd /var/lib/docker/volumes/conf/
[root@docker-node1 conf]# ls
haproxy.cfg
[root@docker-node1 conf]# vim haproxy.cfg
添加以下四行:
listen webcluster
bind *:80
balance roundrobin
server web1 webserver1:80 check inter 3 fall 3 rise 5
server web2 webserver2:80 check inter 3 fall 3 rise 5
[root@docker-node1 ~]# docker load -i haproxy-2.3.tar.gz
[root@docker-node1 ~]# cd test/
[root@docker-node1 test]# vim haproxy.yml
[root@docker-node1 test]# docker compose -f haproxy.yml config
[root@docker-node1 test]# cat haproxy.yml
services:
web1:
image: nginx:latest
container_name: webserver1
restart: always
networks:
- mynet1
expose:
- 80
volumes:
- data_web1:/usr/share/nginx/html
web2:
image: nginx:latest
container_name: webserver2
restart: always
networks:
- mynet1
expose:
- 80
volumes:
- data_web2:/usr/share/nginx/html
haproxy:
image: haproxy:2.3
container_name: haproxy
restart: always
networks:
- mynet1
- mynet2
volumes:
- /var/lib/docker/volumes/conf/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
ports:
- 80:80
networks:
mynet1:
driver: bridge
mynet2:
driver: bridge
volumes:
data_web1:
name: data_web1
data_web2:
name: data_web2
[root@docker-node1 test]# docker compose -f haproxy.yml up -d
[+] Running 7/7
✔ Network test_mynet2 Created 0.3s
✔ Network test_mynet1 Created 0.4s
✔ Volume "data_web1" Created 0.0s
✔ Volume "data_web2" Created 0.0s
✔ Container webserver2 Started 1.8s
✔ Container haproxy Started 2.2s
✔ Container webserver1 Started 2.0s
[root@docker-node1 test]# netstat -antlupe | grep 80
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 0 117692 22682/docker-proxy
tcp6 0 0 :::80 :::* LISTEN 0 118183 22704/docker-proxy
[root@docker-node1 test]#
[root@docker-node1 test]# docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
haproxy haproxy:2.3 "docker-entrypoint.s…" haproxy 47 seconds ago Up 46 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp
webserver1 nginx:latest "/docker-entrypoint.…" web1 47 seconds ago Up 47 seconds 80/tcp
webserver2 nginx:latest "/docker-entrypoint.…" web2 47 seconds ago Up 46 seconds 80/tcp
[root@docker-node1 test]# echo webserver1 > /var/lib/docker/volumes/data_web1/_data/index.html
[root@docker-node1 test]# echo webserver2 > /var/lib/docker/volumes/data_web2/_data/index.html