]# cd /etc/yum.repos.d]# vim docker.repo[docker]name=docker-cebaseurl=https://mirrors.tuna.tsinghua.edu.cn/dockerce/linux/centos/7/x86_64/stable/gpgcheck=0[centos]name=extrasbaseurl=https://mirrors.tuna.tsinghua.edu.cn/centos/7/extras/x86_64gpgcheck=0
#安装docker]# yum install -y docker-ce#编辑docker启动文件,设定其使用iptables的网络设定方式,默认使用nftables[root@docker ~]# vim /usr/lib/systemd/system/docker.serviceExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock--iptables=true]# systemctl enable --now docker]# docker info
下载所有以.rpm结尾的文件
docker常见命令
搜索镜像
[root@Docker-node1 ~]# docker search nginx
NAME DESCRIPTION STARS
OFFICIAL
nginx Official build of Nginx. 20094 [OK]
拉取镜像
#从镜像仓库中拉取镜像
[root@Docker-node1 ~]# docker pull busybox
[root@Docker-node1 ~]# docker pull nginx:1.26-alpine
#查看本地镜像
[root@Docker-node1 ~]# docker images
查看镜像信息
[root@Docker-node1 ~]# docker image inspect nginx:1.26-alpine
#保存镜像
[root@Docker-node1 ~]# docker image save nginx:latest -o nginx-latest.tar.gz
[root@Docker-node1 ~]# docker image save nginx:latest nginx:1.26-alpine -o nginx.tag.gz
#保存所有镜像
[root@Docker-node1 ~]# docker save
docker images | awk 'NR>1{print $1":"$2}'
-o images.tar.gz
删除镜像
[root@Docker-node1 ~]# docker rmi nginx:latest
[root@Docker-node1 ~]# docker rmi
docker images | awk 'NR>1{print $1":"$2}'
docker基本操作
下载保存在本地的镜像停止和运行容器
[root@Docker-node1 ~]# docker stop busybox #停止容器
[root@Docker-node1 ~]# docker kill busybox #杀死容器,可以使用信号
[root@Docker-node1 ~]# docker start busybox #开启停止的容器
在容器中执行命令
docker exec -it mario ifconfig 在名为mario的容器里面查看IP
[root@Docker-node1 ~]# docker ps #查看当前运行容器
[root@Docker-node1 ~]# docker ps -a #查看所有容器
[root@Docker-node1 ~]# docker inspect busybox #查看容器运行的详细信息
停止和运行容器
[root@Docker-node1 ~]# docker stop busybox #停止容器
[root@Docker-node1 ~]# docker kill busybox #杀死容器,可以使用信号
[root@Docker-node1 ~]# docker start busybox #开启停止的容器
删除容器
[root@Docker-node1 ~]# docker rm centos7 #删除停止的容器
[root@Docker-node1 ~]# docker rm -f busybox #删除运行的容器
[root@Docker-node1 ~]# docker container prune -f #删除所有停止的容器
容器内容提交
所以需要执行以下命令
docker commit -m "add leefile" test busybox:v1
系统中的文件和容器中的文件传输
[root@Docker-node1 ~]# docker cp test2:/leefile /mnt #把容器中的文件复制到本机
Successfully copied 1.54kB to /mnt
[root@Docker-node1 ~]# docker cp /etc/fstab test2:/fstab #把本机文件复制到容器中
查询容器内部日志
docker logs web
镜像构建
构建参数
[root@Docker-node1 ~]# mkdir docker/
[root@Docker-node1 ~]# cd docker/
[root@Docker-node1 docker]# touch leefile
[root@Docker-node1 docker]# vim Dockerfile
[root@Docker-node1 docker]# touch leefile{1..3}
[root@Docker-node1 docker]# tar zcf leefile.gz leefile*
[root@Docker-node1 docker]# vim Dockerfile
镜像优化方案
使用最精简镜像
首先,需要以下两个包
[root@docker1 ~]# cd docker/[root@docker1 docker]# vim Dockerfile
搭建docker的私有仓库
Docker私有仓库的主要作用是为组织或个人提供一个安全的环境来存储、管理和分发Docker镜像。与公开仓库相比,私有仓库可以控制镜像的访问权限,确保敏感信息和专有软件不被未授权访问。这对于保护知识产权、维护项目的隐私和安全至关重要。私有仓库还提供了更好的管理和监控功能,允许组织跟踪镜像的使用情况和历史记录,以及集成自动化构建和部署流程,提高开发效率
加载本地的registry镜像
查看上传的镜像
curl 172.25.254.100:5000/v2/_catalog
为Registry提加密传输
生成认证key和证书
[root@docker ~]# openssl req -newkey rsa:4096 \
-nodes -sha256 -keyout certs/timinglee.org.key \
-addext "subjectAltName = DNS:reg.timinglee.org" \ #指定备用名称
-x509 -days 365 -out certs/timinglee.org.crt
[root@docker ~]# docker run -d -p 443:443 --restart=always --name registry \
\> --name registry -v /opt/registry:/var/lib/registry \
\> -v /root/certs:/certs \
\> -e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
\> -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/timinglee.org.crt \
\> -e REGISTRY_HTTP_TLS_KEY=/certs/timinglee.org.key registry
[root@docker docker]# mkdir /etc/docker/certs.d/reg.timinglee.org/ -p
[root@docker docker]# cp /root/certs/timinglee.org.crt
/etc/docker/certs.d/reg.timinglee.org/ca.crt
[root@docker docker]# systemctl restart docker
测试查看
docker tag nginx:latest reg.ljx.org/nginx:latest
docker push reg.ljx.org/nginx:latest
为仓库建立登陆认证
Docker仓库的登录认证主要用于控制对私有仓库的访问权限,确保只有经过授权的用户才能拉取或推送镜像。这是通过在Docker客户端和Docker Registry之间建立一个安全的身份验证机制来实现的。
认证流程
-
用户登录:用户使用
docker login
命令并提供仓库地址、用户名和密码来登录。如果用户在本地没有登录凭证,Docker会将用户名和密码以Base64编码的形式存储在本地的配置文件$HOME/.docker/config.json
中。 -
凭证存储:Docker默认将凭证以明文形式存储在配置文件中,这可能会带来安全隐患。为了提高安全性,可以配置凭证存储帮助程序,将凭证安全地存储在操作系统提供的凭证管理器中。
-
认证机制:当用户尝试拉取或推送镜像时,Docker会检查本地配置文件中是否存在对应仓库的认证信息。如果存在,Docker会使用这些凭证与仓库进行通信。如果仓库配置了额外的认证机制(如HTTP基本认证、令牌认证等),Docker会根据仓库的要求提供相应的凭证23。
-
安全优化:为了进一步增强安全性,可以在Docker Registry中配置HTTP基本认证,使用如
htpasswd
工具生成加密的用户密码文件,并在启动Docker Registry容器时通过环境变量指定认证文件的路径。
通过这些认证机制,Docker确保了只有经过验证的用户才能与私有仓库交互,从而保护了镜像不被未授权访问。这对于保护企业的知识产权和敏感数据尤为重要
安装建立认证文件的工具包
[root@docker docker]# dnf install httpd-tools -y
\#建立认证文件
[root@docker ~]# mkdir auth
[root@docker ~]# htpasswd -Bc auth/htpasswd ljx #-B 强制使用最安全加密方式,
默认用md5加密
New password:
Re-type new password:
Adding password for user ljx
#添加认证到registry容器中
[root@docker ~]# docker run -d -p 443:443 --restart=always --name registry \
\> --name registry -v /opt/registry:/var/lib/registry \
\> -v /root/certs:/certs \
\> -e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
\> -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/timinglee.org.crt \
\> -e REGISTRY_HTTP_TLS_KEY=/certs/timinglee.org.key \
\> -v /root/auth:/auth \
\> -e "REGISTRY_AUTH=htpasswd" \
\> -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
\> -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
\> registry
harbor
Harbor 是一个开源的企业级 Docker 镜像仓库,它提供了安全、可信赖的镜像存储和分发功能。Harbor 的主要作用包括:
- 多用户管控:基于角色访问控制和项目隔离,支持多用户系统,可以对接 AD/LDAP 或通过 OIDC 机制对接其他用户系统。
- 镜像管理策略:包括存储配额、制品保留、漏洞扫描、来源签名、不可变制品和垃圾回收等。
- 安全与合规:提供身份认证、扫描和 CVE 例外规则等安全功能,支持镜像签名和内容扫描,确保制品管理的合规性。
- 互操作性:支持 Webhook、内容远程复制、可插拔扫描器、REST API 和机器人账号等,方便与不同系统的集成。
- 镜像复制:可以在不同的 Harbor 实例之间复制镜像,支持多种触发模式和过滤器。
- 图形管理界面:提供用户友好的 Web 界面进行操作和管理。
- 审计管理:记录所有对镜像仓库的操作,便于审计和问题排查。
Harbor 最初由 VMware 公司开发,并在 2018 年捐赠给 CNCF(云原生计算基金会),成为社区共同维护的开源项目。它旨在满足企业安全合规的需求,支持云原生应用的部署和管理。
安装harbor
解压harbor包
[root@docker ~]# cd harbor/
[root@docker harbor]# cp harbor.yml.tmpl harbor.yml
[root@docker harbor]# vim harbor.yml
开始安装
./install.sh --with-chartmiseum
进入harbor界面
在虚拟机登录域名进行上传镜像
上传镜像
docker网络
docker原生bridge网路
[root@docker1 harbor]# docker run -d -it --name test -p 80:80 busybox:latest
docker原生网络host
docker原生网络none
没有网络了
docker的自定义网络
自定义桥接网络
新建docker网络
[root@docker1 harbor]# docker run -it --name test1 busybox
[root@docker1 harbor]# docker run -it --name test2 busybox
自定义网络前,可以ping通IP,但不能ping容器名称
使用自定义网络后便可以通过容器名称ping通
[root@docker1 harbor]# docker run -it --name test1 --network ljx_net1 busybox
[root@docker1 harbor]# docker run -it --name test2 --network ljx_net1 busybox
如何让不同的自定义网络互通
开启两个容器,分别是web1和test
这样test容器也多了一个网络
joined容器网络
容器网络作用
在Docker中,joined
容器网络模式允许将一个容器挂载到另一个容器上,实现资源共享和通信。这种模式下,容器可以共享网络栈、网卡和配置信息,使得容器之间可以通过localhost
或127.0.0.1
直接通信。joined
容器模式特别适合于不同容器中的程序需要高效快速地通信的场景,例如web服务器与应用服务器之间的通信,或者是网络监控程序需要监控其他容器的网络流量23.
创建MySQL和php容器
#运行phpmysqladmin
[root@docker ~]# docker run -d --name mysqladmin --network ljxnet1 \
-e PMA_ARBITRARY=1 \ #在web页面中可以手动输入数据库地址和端口
-p 80:80 phpmyadmin:latest
[root@docker ~]# docker run -d --name mysql \
-e MYSQL_ROOT_PASSWORD='lee' \ #设定数据库密码
--network container:mysqladmin \ #把数据库容器添加到phpmyadmin容器中
mysql:5.7
访问172.25.254.100
进入数据库,可以和其他数据库一样操作
创建了一个库
外网访问docker容器
docker run -d --name webserver -p 80:80 nginx
iptables -t nat -nL 查看策略
docker跨主机网络
macvlan网络方式实现跨主机通信
MacVLAN网络方式的原理
MacVLAN是Linux内核支持的一种网络接口技术,它允许在物理网络接口上创建多个虚拟网络接口,每个虚拟接口都有独立的MAC地址。MacVLAN的工作原理是在物理网卡上虚拟出多个网络接口,这些接口可以配置各自的IP地址,并且可以直接在数据链路层进行网络数据的转发。由于MacVLAN子接口和物理网卡共享同一个物理介质,因此需要将物理网卡设置为混杂模式,以接收所有MAC地址的数据包2。
MacVLAN网络方式的作用
MacVLAN网络方式的主要作用是提供网络隔离和灵活性。它可以用于虚拟机或容器,使得这些虚拟环境能够拥有独立的网络身份,从而实现与物理网络的直接通信。MacVLAN不依赖于网桥,因此可以减少网络配置的复杂性,并且可以提高网络性能,因为数据包不需要经过额外的网络设备转发24。
在跨主机通信的场景中,MacVLAN可以配置为桥接模式或私有模式,其中桥接模式允许虚拟机或容器像物理设备一样直接连接到物理网络,而私有模式则将虚拟接口与主机的网络隔离,但仍然可以通过主机进行通信。通过适当的网络配置和路由设置,MacVLAN可以实现不同主机上的虚拟机或容器之间的通信。
在两台docker主机上各添加一块网卡,打开网卡混杂模式
两台主机添加macvlan网路
[root@docker ~]# docker network create \
-d macvlan \
--subnet 1.1.1.0/24 \
--gateway 1.1.1.1 \
-o parent=eth1 macvlan1
docker run -it --name test1 --network macvlan1 --ip 1.1.1.6 busybox
docker run -it --name test2 --network macvlan1 --ip 1.1.1.2 busybox
Docker 数据卷管理及优化
bind mount 数据卷
docker managed数据卷
[root@docker volumes]# docker run -d --name mysql -e MYSQL_ROOT_PASSWORD='lee' mysql:5.7
[root@docker1 volumes]# touch f2936e9000b20850f69d1fc41eb643dc3609bd11f1caef0c4c13fa5f2f5384cd/_data/leefile
重新进入mysql容器进行查看创建的leefle文件
清理未使用的 Docker 数据卷
[root@docker ~]# docker volume prune
\1. 在执行 docker volume prune 命令之前,请确保你确实不再需要这些数据卷中的数据,因为
该操作是不可逆的,一旦删除数据将无法恢复。
\2. 如果有重要的数据存储在数据卷中,建议先进行备份,或者确保数据已经被妥善保存到其他地
方。
新建数据卷
数据卷容器(Data Volume Container)
建立数据卷容器
备份与迁移数据卷
备份数据卷
数据恢复
登录之前所创建的数据卷进行数据恢复
Docker 的安全优化
启动cgroup1
[root@docker1 ~]# docker run -d --name web nginx
查看pid
资源没有被隔离
Docker的资源限制
限制cpu使用
Docker限制CPU使用的原理
Docker容器限制CPU使用的原理基于Linux内核的Cgroups(Control Groups)功能。Cgroups允许对进程组(在Docker中即为容器)的资源使用进行限制和管理。通过Cgroups,可以限制容器可以使用的CPU时间、内存、磁盘I/O等资源。
在CPU资源管理方面,Cgroups提供了cpu
子系统,它可以设置CPU的使用配额和周期。具体来说,可以通过设置cpu.cfs_quota_us
来限制容器在一个CFS(Completely Fair Scheduler)调度周期内可以使用的CPU时间,以及通过cpu.shares
来设置容器相对于其他容器的CPU资源分配权重。
Docker限制CPU使用的作用
限制Docker容器的CPU使用有几个重要作用:
- 资源隔离:确保容器不会占用过多的CPU资源,影响宿主机上运行的其他进程或容器的性能。
- 性能保障:通过限制CPU资源,可以为容器提供一个稳定的执行环境,避免因CPU资源争夺而导致的性能波动。
- 资源优化:合理配置CPU资源限制可以提高整个系统的资源利用率,确保系统中的每个容器都能获得必要的计算资源。
- 避免资源耗尽:在多租户环境中,限制CPU使用可以防止单个容器消耗过多资源,导致整个系统资源耗尽。
通过这些限制,Docker容器能够在保证应用程序运行所需资源的同时,与其他容器和宿主机共享系统资源,从而实现有效的资源管理和系统稳定性
#关闭cpu的核心,当cpu都不空闲下才会出现争抢的情况,为了实验效果我们可以关闭一个cpu核心
root@docker ~]# echo 0 > /sys/devices/system/cpu/cpu1/online
cpu cores表示cpu核心数
没有限制前,cpu占用率为99%
[root@docker1 ~]# docker run -it --rm --name test1 ubuntu
root@1de28b2616a7:/# dd if=/dev/zero of=/dev/null &
[1] 9
root@1de28b2616a7:/# top
限制后
cpu占用率为20%
[root@docker1 ~]# docker run -it --rm --name test3 --cpu-period 100000 --cpu-quota 20000 ubuntu
root@1de28b2616a7:/# dd if=/dev/zero of=/dev/null &
[1] 9
root@1de28b2616a7:/# top
限制cpu的优先级
优先级为100,#设定cpu优先
级,最大为1024,值越大优先级越高
[root@docker1 ~]# docker run -it --rm --cpu-shares 100 ubuntu
root@650c563427ba:/# dd if=/dev/zero of=/dev/null &
[1] 8
root@650c563427ba:/# top
默认优先级
[root@docker1 ~]# docker run -it --rm ubuntu
root@1de28b2616a7:/# dd if=/dev/zero of=/dev/null &
[1] 9
root@1de28b2616a7:/# top
查看cpu使用率
限制内存使用
Docker限制内存使用的原理
Docker通过Linux内核的控制组(cgroups)功能来限制容器的内存使用。cgroups允许对系统资源进行分组和限制,确保容器不会消耗超过分配的资源。在Docker中,可以通过--memory
(或-m
)标志来设置容器的硬内存限制,即容器可以使用的最大内存量。如果容器尝试使用超过这个限制的内存,系统会根据配置触发OOM(Out of Memory)杀手来终止容器进程,以保护宿主机的稳定性。
Docker限制内存使用的作用
限制内存使用的主要作用是确保容器不会消耗过多的系统资源,从而避免对宿主机或其他容器的性能造成影响。在生产环境中,资源限制有助于维护系统的稳定性和可预测性,防止单个容器的内存泄漏或资源消耗失控导致整个系统的不稳定。
此外,Docker还提供了--memory-swap
参数来设置容器的内存交换(swap)限制,即容器可以使用的虚拟内存大小。这允许容器在物理内存不足时使用磁盘空间作为额外的内存,但这可能会影响性能,因为磁盘I/O速度远慢于RAM1。
还有--memory-reservation
和--memory-swappiness
参数,分别用于设置内存的软限制和控制容器内存交换的倾向性。软限制可以在系统内存紧张时作为一个提示,而--memory-swappiness
参数可以调整容器内部进程使用swap空间的意愿。
通过这些机制,Docker提供了灵活的内存管理选项,以适应不同的部署场景和资源管理需求
开启容器并限制容器使用内存大小
#测试容器内存限制,在容器中我们测试内存限制效果不是很明显,可以利用工具模拟容器在内存中写入数据
#在系统中/dev/shm这个目录被挂在到内存中
写入数据
用x1控制器显示
[root@docker ~]# mkdir -p /sys/fs/cgroup/memory/x1/
[root@docker ~]# echo 209715200 > /sys/fs/cgroup/memory/x1/memory.limit_in_bytes
#内存可用大小限制
[root@docker ~]# cat /sys/fs/cgroup/memory/x1/tasks #此控制器被那个进程调用
[root@docker ~]# cgexec -g memory:x1 dd if=/dev/zero of=/dev/shm/bigfile bs=1M
count=100
echo 209715200 >/sys/fs/cgroup/memory/x1/memory.memsw.limit_in_bytes #内存+swap控制
限制docker的磁盘io
[root@docker ~]# docker run -it --rm \
--device-write-bps \ #指定容器使用磁盘io的速率
/dev/nvme0n1:30M \ #/dev/nvme0n1是指定系统的磁盘,30M即每秒30M数据
ubuntu
刚开始速度不匹配是因为系统的缓存机制
root@a4e9567a666d:/# dd if=/dev/zero of=bigfile bs=1M count=100 oflag=direct #设定dd命令直接写入磁盘
写入速度和我们设定的30M差不多
Docker的安全加固
Docker默认隔离性
#虽然我们限制了容器的内容使用情况,但是查看到的信息依然是系统中内存的使用信息,并没有隔离开
解决Docker的默认隔离性
#在rhel9中lxcfs是被包含在epel源中,我们可以直接下载安装包进行安装
[root@docker ~]# ls lxcfs
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
dnf install lxc* -y
运行lxcfs并解决容器隔离性
[root@docker ~]# lxcfs /var/lib/lxcfs &
运行测试
容器特权
在容器中默认情况下即使我是容器的超级用户也无法修改某些系统设定,比如网络
这是因为容器使用的很多资源都是和系统真实主机公用的,如果允许容器修改这些重要资源,系统的稳
定性会变的非常差
但是由于某些需要求,容器需要控制一些默认控制不了的资源,如何解决此问题,这时我们就要设置容
器特权
如果添加了--privileged 参数开启容器,容器获得权限近乎于宿主机的root用户
容器特权的白名单
--privileged=true 的权限非常大,接近于宿主机的权限,为了防止用户的滥用,需要增加限制,只提供
给容器必须的权限。此时Docker 提供了权限白名单的机制,使用--cap-add添加必要的权限
capabilities手册地址:capabilities(7) - Linux manual page
限制容器对网络有root权限
[root@docker1 ~]# docker run --rm -it --cap-add NET_ADMIN busybox
可以添加网络,但不能管理磁盘
容器编排工具Docker Compose
vim /test/docker-compose.yml
检测运行
停止服务
重启服务
服务状态查看
构建和重新构建服务(了解)
Docker Compose 的yml文件
镜像(image):
[root@docker test]# docker compose -f docker-compose.yml up -d #会去仓库拉去镜
像
[+] Running 1/1
! test1 Warning pull access denied for test1, repository does not exist or
may require 'docker login': denied: requested acces...
[root@docker test]# docker compose -f docker-compose.yml up --build #会先构建镜像后
启动容器
端口映射(ports)
环境变量(environment):
存储卷(volumes):
网络(networks):
命令(command)
覆盖容器启动时默认执行的命令。例如, command: python app.py 指定容器启动时运行
python app.py 命令
二、网络(networks)
[root@docker1 test]# cat docker-compose.yml
services:
web:
image: busybox:latest
command: ["/bin/sh","-c","sleep 3000"]
restart: always
network_mode: default
container_name: busybox
test1:
image: busybox:latest
command: ["/bin/sh","-c","sleep 3000"]
restart: always
container_name: busybox1
networks:
- mynet1
test3:
image: busybox:latest
command: ["/bin/sh","-c","sleep 3000"]
restart: always
container_name: busybox2
networks:
- mynet1
- mynet2
networks:
mynet1:
driver: bridgedefault:
external: true
name: bridgemynet2:
ipam:
driver: default
config:- subnet: 172.28.0.0/16
gateway: 172.28.0.254
企业示例
利用容器编排完成haproxy和nginx负载均衡架构实施
[root@docker1 ~]# dnf install haproxy --downloadonly --downloaddir=/mnt
[root@docker1 ~]# rpm2cpio haproxy-2.4.17-6.el9.x86_64.rpm | cpio -idum
cp /mnt/etc/haproxy/haproxy.cfg /var/lib/docker/volumes/conf/haproxy.cfg
vim /var/lib/docker/volumes/conf/haproxy.cfg
[root@docker1 ~]# cat haproxy.yml
services:
web1:
image: nginx:latest
container_name: webserver1
restart: always
networks:
- mynet1
expose:
- 80
volumes:
- /docker/web/html1:/usr/share/nginx/html
web2:
image: nginx:latest
container_name: webserver2
restart: always
networks:
- mynet1
expose:
- 80
volumes:
- /docker/web/html2:/usr/share/nginx/html
haproxy:
image: haproxy:2.3
container_name: haproxy
restart: always
networks:
- mynet1
- mynet2
volumes:
- /var/lib/docker/volumes/conf/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
ports:
- 80:80
networks:
mynet1:
driver: bridge
mynet2:
driver: bridge
查看服务状态
均成功启动
测试: