0
点赞
收藏
分享

微信扫一扫

Docker从入门到精通

一、镜像基础命令
1、docker version

[root@DY-Ubuntu-01 ~]#docker version                #查看 Docker 版本

2、docker info

[root@DY-Ubuntu-01 ~]#docker info
Client:
Context: default
Debug Mode: false #client 端是否开启 debug

Server:
Containers: 0 #当前主机运行的容器总数
Running: 0 #有几个容器是正在运行的
Paused: 0 #有几个容器是暂停的
Stopped: 0 #有几个容器是停止的
Images: 0 #当前服务器的镜像数
Server Version: 20.10.19 #服务端版本
Storage Driver: overlay2 #正在使用的存储引擎
Backing Filesystem: xfs #后端文件系统,即服务器的磁盘文件系统
Supports d_type: true #是否支持 d_type
Native Overlay Diff: true #是否支持差异数据存储
userxattr: false
Logging Driver: json-file #日志类型
Cgroup Driver: cgroupfs #Cgroups 类型
Cgroup Version: 1
Plugins: #插件
Volume: local #卷
Network: bridge host ipvlan macvlan null overlay # overlay 跨主机通信
Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog # 日志类型
Swarm: inactive #是否支持 swarm
Runtimes: runc io.containerd.runc.v2 io.containerd.runtime.v1.linux #已安装的容器运行时
Default Runtime: runc #默认使用的容器运行时
Init Binary: docker-init #初始化容器的守护进程,即 pid 为 1 的进程
containerd version: 9cd3357b7fd7218e4aec3eae239db1f68a5a6ec6 #版本
runc version: v1.1.4-0-g5fd4c4d1 #runc 版本
init version: de40ad0 #init 版本
Security Options: #安全选项
apparmor #安全模块,https://docs.docker.com/engine/security/apparmor/
seccomp #安全计算模块,即制容器操作,https://docs.docker.com/engine/security/seccomp
Profile: default #默认的配置文件
Kernel Version: 5.4.0-126-generic #宿主机内核版本
Operating System: Ubuntu 20.04.4 LTS #宿主机操作系统
OSType: linux #宿主机操作系统类型
Architecture: x86_64 #宿主机架构
CPUs: 2 #宿主机 CPU 数量
Total Memory: 3.84GiB #宿主机总内存
Name: DY-Ubuntu-01 #宿主机 hostname
ID: YZQ6:756A:YPQR:XKA7:POII:EQ6Z:KUPN:BHPK:Q6QK:GYCX:56RA:PWJY #宿主机 ID
Docker Root Dir: /var/lib/docker #宿主机关于docker数据的保存目录
Debug Mode: false #server 端是否开启 debug
Registry: https://index.docker.io/v1/ #仓库路径
Labels:
Experimental: false #是否测试版
Insecure Registries:
127.0.0.0/8 #非安全的镜像仓库
Registry Mirrors:
https://pgavrk5n.mirror.aliyuncs.com/ #镜像仓库
Live Restore Enabled: false #是否开启活动重启 (重启docker-daemon 不关闭容器 )
Product License: Community Engine
WARNING: No swap limit support #系统警告信息 (没有开启 swap 资源限制 )

范例: 解决SWAP报警提示 " WARNING: No swap limit support "

[root@DY-Ubuntu-01 ~]#vim /etc/default/grub
GRUB_CMDLINE_LINUX="net.ifnames=0 biosdevname=0 swapaccount=1" #修改此行
[root@DY-Ubuntu-01 ~]#update-grub
[root@DY-Ubuntu-01 ~]#reboot

3、docker search、pull

[root@DY-Ubuntu-01 ~]#docker search nginx              #搜索nginx镜像,默认版本latest默认从docker官网搜索
[root@DY-Ubuntu-01 ~]#docker pull nginx #拉取nginx镜像,默认从docker官网拉取
[root@DY-Ubuntu-01 ~]#docker image history nginx #查看镜像分层历史
[root@DY-Ubuntu-01 ~]#docker inspect nginx #查看镜像详细信息
[root@DY-Ubuntu-01 ~]#docker save nginx -o nginx.tar #导出nginx镜像
[root@DY-Ubuntu-01 ~]#docker images #列出镜像文件
[root@DY-Ubuntu-01 ~]#docker search -f=stars=100 nginx #搜索点赞大于100的nginx镜像
[root@DY-Ubuntu-01 ~]#docker search --limit 3 nginx #搜索三个结果

[root@node1 ~]# docker run -it -d --name alpine-1 --rm alpine     #后台交互运行一个名称为alpine-1的alpine容器,停止容器后删除容器
[root@node1 ~]# docker exec -it alpine-1 /bin/sh #进入alpine-1容器,指定bash类型为sh
/ # vi /etc/apk/repositories #修改源替换成阿里源
https://mirrors.aliyun.com/alpine/v3.15/main
https://mirrors.aliyun.com/alpine/v3.15/community

/ # apk update #更新源
/ # apk add vim #安装软件
/ # apk del openssh #删除软件
/ # apk info nginx #显示软件的详细信息
/ # apk manifest nginx #显示校验
# Debian(ubuntu)系统建议安装的基础包
# apt update #安装软件前需要先更新索引
# apt install procps #提供top,ps,free等命令
# apt install psmisc #提供pstree,killall等命令
# apt install iputils-ping #提供ping命令
# apt install net-tools #提供netstat网络工具等
# apt install iproute2 #提供ip,ss网络工具等
[root@node1 ~]# docker pull hello-world
Using default tag: latest #默认下载最新版本
latest: Pulling from library/hello-world
2db29710123e: Pull complete #分层下载
Digest: sha256:2498fce14358aa50ead0cc6c19990fc6ff866ce72aeb5546e1d59caac3d0d60f #摘要
Status: Downloaded newer image for hello-world:latest #状态
docker.io/library/hello-world:latest #下载的完整地址

[root@node1 ~]# ll /var/lib/docker/overlay2/镜像ID        #镜像下载保存的路径
注意: 镜像下载完成后,会自动解压缩,比官网显示的可能会大很多,如: centos8.1.1911下载时只有70MB,下载完后显示237MB

4、阿里云加速

浏览器打开http://cr.console.aliyun.com,注册或登录阿里云账号,点击左侧的镜像加速器,将会得到一个专属的加速地址,而且有使用配置说明

修改daemon配置文件/etc/docker/daemon.json来使用加速器
mkdir -p /etc/docker
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://docker.mirrors.ustc.edu.cn","http://hub-mirror.c.163.com/","https://si7y70hh.mirror.aliyuncs.com"]
}
EOF
#网易云: http://hub-mirror.c.163.com/
#中科大: https://docker.mirrors.ustc.edu.cn
#腾讯云: https://mirror.ccs.tencentyun.com
#七牛云: https://reg-mirror.qiniu.com
systemctl daemon-reload
systemctl restart docker

5、查看本地镜像

[root@node1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE

REPOSITORY #镜像所属的仓库名称
TAG #镜像版本号(标识符),默认为latest
IMAGE ID #镜像唯一ID标识,如果ID相同,说明是同一个镜像有多个名称
CREATED #镜像在仓库中被创建时间
VIRTUAL SIZE #镜像的大小

[root@node1 ~]# docker images -q              #查看镜像id
c059bfaa849c
feb5d9fea6a5
[root@node1 ~]# docker images --no-trunc #显示完整的ImageID
REPOSITORY TAG IMAGE ID CREATED SIZE
alpine latest sha256:c059bfaa849c4d8e4aecaeb3a10c2d9b3d85f5165c66ad3a4d937758128c4d18 10 months ago 5.59MB
hello-world latest sha256:feb5d9fea6a5e9606aa995e879d862b825965ba48de054caab5ef356dc6b3412 12 months ago 13.3kB

[root@node1 ~]# docker image inspect alpine #查看指定镜像的详细信息

6、镜像导出

#导出单个镜像
#方法1
[root@node1 ~]# docker save -o alpine.tar alpine
#方法2
[root@node1 ~]# docker save alpine > alpine1.tar

=========================
#导出多个镜像至一个文件
#方法1
[root@node1 ~]# docker save -o all1.tar alpine hello-world
#方法2
[root@node1 ~]# docker save alpine hello-world -o all.tar
#方法3
[root@node1 ~]# docker save alpine hello-world > all2.tar

==========================
#导出所有镜像至一个文件
#方法1
[root@node1 ~]# docker save `docker images | awk 'NR>1{print $1":"$2}'` -o all4.tar #导出所有镜像到一个打包文件,此方法导入后可以看REPOSITORY和TAG
#方法2
[root@node1 ~]# docker image save `docker image ls --format "{{.Repository}}:{{.Tag}}"` -o all5.tar
#将所有镜像导入到一个文件中,此方法导入后可以看REPOSITORY和TAG

============================
#导出所有镜像至不同的文件中
#方法1
[root@node1 ~]# docker images | awk 'NR!=1{print $1,$2}' | while read repo tag ;do docker save ${repo}:${tag} -o ${repo}-${tag}.tar; done #导出所有镜像至不同的文件中

#方法2
[root@node1 ~]# for i in `docker images --format "{{.Repository}}:{{.Tag}}"`; do docker save $i -o `echo $i|cut -d: -f1`.tar; done #导出所有镜像至不同的文件中

7、镜像导入

#方法1
[root@DY-Ubuntu-01 ~]#docker load -i all5.tar
#方法2
[root@DY-Ubuntu-01 ~]#docker load < all5.tar

8、删除镜像

[root@DY-Ubuntu-01 ~]#docker rmi nginx
[root@DY-Ubuntu-01 ~]#docker rmi -f hello-world #强制删除正在使用的镜像,也会删除对应的容器
[root@DY-Ubuntu-01 ~]#docker rmi nginx httpd #删除多个镜像
================================================
[root@node1 ~]# docker image prune #清理dangling虚无镜像(没被标记且没被其它任何镜像引用的镜像)
WARNING! This will remove all dangling images.
Are you sure you want to continue? [y/N] y
Total reclaimed space: 0B

[root@node1 ~]# docker image prune -a -f #清理dangling虚无镜像以及不再使用的镜像
Deleted Images:
untagged: hello-world:latest
untagged: hello-world@sha256:2498fce14358aa50ead0cc6c19990fc6ff866ce72aeb5546e1d59caac3d0d60f
deleted: sha256:feb5d9fea6a5e9606aa995e879d862b825965ba48de054caab5ef356dc6b3412
deleted: sha256:e07ee1baac5fae6a26f30cabfe54a36d3402f96afda318fe0a96cec4ca393359
untagged: nginx:latest
untagged: nginx@sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31
deleted: sha256:605c77e624ddb75e6110f997c58876baa13f8754486b461117934b24a9dc3a85
deleted: sha256:b625d8e29573fa369e799ca7c5df8b7a902126d2b7cbeb390af59e4b9e1210c5
deleted: sha256:7850d382fb05e393e211067c5ca0aada2111fcbe550a90fed04d1c634bd31a14
deleted: sha256:02b80ac2055edd757a996c3d554e6a8906fd3521e14d1227440afd5163a5f1c4
deleted: sha256:b92aa5824592ecb46e6d169f8e694a99150ccef01a2aabea7b9c02356cdabe7c
deleted: sha256:780238f18c540007376dd5e904f583896a69fe620876cabc06977a3af4ba4fb5

9、镜像打标签

#TARGET_IMAGE[:TAG]格式一般形式
仓库主机FQDN或IP[:端口]/项目名(或用户名)/image名字:版本
[root@DY-Ubuntu-01 ~]#docker tag alpine alpine:10.15

10、命令总结: 企业使用镜像及常见操作: 搜索、下载、导出、导入、删除

docker search centos
docker pull alpine
docker images
docker save > /opt/centos.tar #centos #导出镜像
docker load -i /opt/centos.tar #导入本地镜像
docker rmi 镜像ID/镜像名称 #删除指定ID的镜像,此镜像对应容器正启动镜像不能被删除,除非将容器全部关闭
[root@DY-Ubuntu-01 ~]#docker run -it -d -p 4000:4000 docs/docker.github.io:latest #运行docker官方文档容器(用浏览器访问http://localhost:4000/可以看到类似官网的docker文档资料)

二、容器操作基础命令
1、启动容器

docker run [选项] [镜像名] [shell命令] [参数]
#选项:
-i, --interactive Keep STDIN open even if not attached,通常和-t一起使用
-t, --tty 分配pseudo-TTY,通常和-i一起使用,注意对应的容器必须运行shell才支持进入
-d, --detach Run container in background and print container ID,台后运行,默认前台
--name string Assign a name to the container
--h, --hostname string Container host name
--rm Automatically remove the container when it exits
-p, --publish list Publish a container's port(s) to the host
-P, --publish-all Publish all exposed ports to random ports
--dns list Set custom DNS servers
--entrypoint string Overwrite the default ENTRYPOINT of the image
--restart policy
--privileged Give extended privileges to container
-e, --env=[] Set environment variables
--env-file=[] Read in a line delimited file of environment variables

[root@DY-Ubuntu-01 ~]#docker run hello-world

从容器内退出,并停止容器
exit
从容器内退出,且容器不停止
同时按三个键,ctrl+p+q

[root@DY-Ubuntu-01 ~]#docker run busybox echo "hello world"    ##启动的容器在执行完shell命令就退出,用于测试

[root@DY-Ubuntu-01 ~]#docker run --name a1 alpine       #指定容器名称

[root@DY-Ubuntu-01 ~]#docker run -it busybox sh        # 运行交互式容器
/ # exit
[root@DY-Ubuntu-01 ~]#docker run -it --name a2 -h a2.wang.org alpine #设置运行容器内的主机名

[root@DY-Ubuntu-01 ~]#docker run --rm alpine cat /etc/issue     #一次性运行容器,退出后立即删除,用于测试
Welcome to Alpine Linux 3.15
Kernel \r on an \m (\l)

[root@DY-Ubuntu-01 ~]#docker run -d --name nginx -p 80:80 --restart=always nginx    #开机自动运行容器

[root@DY-Ubuntu-01 ~]#docker run -it --privileged centos          #使用--privileged 让容器获取 root 权限

[root@DY-Ubuntu-01 ~]#docker run -it -d -p 4000:4000 docs/docker.github.io:latest   #运行docker官方文档容器(用浏览器访问http://localhost:4000/可以看到类似官网的docker文档资料)

2、查看容器

[root@DY-Ubuntu-01 ~]#docker ps          #显示运行的容器             
[root@DY-Ubuntu-01 ~]#docker ps -a #显示全部容器,包括退出状态的容器
[root@DY-Ubuntu-01 ~]#docker ps -a -q #只显示容器ID
[root@DY-Ubuntu-01 ~]#docker ps -a -s #显示容器大小
[root@DY-Ubuntu-01 ~]#docker ps -l #显示最新创建的容器(停止的容器也能显示)
[root@DY-Ubuntu-01 ~]#docker ps -f 'status=exited' ##查看退出状态的容器,注意:exited不要大写
[root@DY-Ubuntu-01 ~]#docker top http #查看容器内的进程
[root@DY-Ubuntu-01 ~]#docker stats http #查看容器资源使用情况
[root@DY-Ubuntu-01 ~]#docker inspect http #查看容器的详细信息

#选择性查看镜像信息
[root@DY-Ubuntu-01 ~]#docker inspect -f "{{.Metadata}}" httpd:latest
[root@DY-Ubuntu-01 ~]#docker inspect -f "{{.RootFS}}" httpd:latest
[root@DY-Ubuntu-01 ~]#docker inspect -f "{{.Created}}" httpd:latest
[root@DY-Ubuntu-01 ~]#docker inspect -f "{{.RepoTags}}" httpd:latest

3、删除容器

[root@DY-Ubuntu-01 ~]#docker rm d863d56931e3      #删除停止的容器
[root@DY-Ubuntu-01 ~]#docker rm -f nginx #强行删除正在运行的容器
[root@DY-Ubuntu-01 ~]#docker rm `docker ps -qf status=exited` #删除指定状态的容器
[root@DY-Ubuntu-01 ~]#docker container prune -f #删除所有停止的容器
[root@DY-Ubuntu-01 ~]#docker rm -f `docker ps -a -q` #删除所有容器
[root@DY-Ubuntu-01 ~]#docker ps -a -q | xargs docker rm -f #删除所有容器

# 定义删除所有容器的别名
[root@DY-Ubuntu-01 ~]#vim .bashrc
[root@DY-Ubuntu-01 ~]#. .bashrc
alias rmc='docker rm -f `docker ps -qa`'

4、启动和停止容器

[root@DY-Ubuntu-01 ~]#docker stop nginx1                    #停止容器
[root@DY-Ubuntu-01 ~]#docker start nginx1 #启动容器

[root@DY-Ubuntu-01 ~]#docker stop `docker ps -a -q` #停止所有容器
[root@DY-Ubuntu-01 ~]#docker start `docker ps -a -q` #启动所有容器

5、暂停和恢复容器

[root@DY-Ubuntu-01 ~]#docker pause nginx1          #暂停容器
[root@DY-Ubuntu-01 ~]#docker unpause nginx1 #恢复容器

6、给正在运行的容器发信号

docker kill 可以给容器发信号,默认号SIGKILL,即9信号

[root@DY-Ubuntu-01 ~]#docker kill nginx1 #关闭容器
[root@DY-Ubuntu-01 ~]#docker kill `docker ps -a -q` #强制关闭所有运行中的容器

7、进入正在运行的容器

[root@DY-Ubuntu-01 ~]#docker attach 133ecc9bfcac            #进入容器,同时在第二个终端attach到同一个容器,执行命令,可以在前一终端看到显示图面是同步的

[root@DY-Ubuntu-01 ~]#docker exec 133ecc9bfcac cat /etc/os-release        #执行一次性命令
[root@DY-Ubuntu-01 ~]#docker exec -it 133ecc9bfcac bash #进入容器,执行命令,exit退出但容器不停止

8、暴露所有容器端口

[root@DY-Ubuntu-01 ~]#docker run -d -P --name nginx1 nginx           #映射容器所有暴露端口至随机本地端口
[root@DY-Ubuntu-01 ~]#docker port nginx1 #查看容器的端口映射关系
80/tcp -> 0.0.0.0:49153
80/tcp -> :::49153
[root@DY-Ubuntu-01 ~]#iptables -t nat -vnL #自动生成Iptables规则
[root@DY-Ubuntu-01 ~]#iptables -S -t nat

9、指定端口映射

[root@DY-Ubuntu-01 ~]#docker run -d --name nginx2 -p 80 nginx      #容器80端口映射宿主机本地随机端口
[root@DY-Ubuntu-01 ~]#docker run -d --name nginx3 -p 81:80 nginx #容器80端口映射到宿主机本地端口81
[root@DY-Ubuntu-01 ~]#docker run -d --name nginx4 -p 192.168.100.201:82:80 nginx #宿主机本地IP:宿主机本地端口:容器端口
[root@DY-Ubuntu-01 ~]#docker run -d --name nginx5 -p 192.168.100.201::80 nginx #宿主机本地IP:宿主机本地随机端口:容器端口,默认从32768开始
[root@DY-Ubuntu-01 ~]#docker run -d --name nginx6 -p 192.168.100.201:83:80/udp nginx #宿主机本机ip:宿主机本地端口:容器端口/协议,默认为tcp协议
[root@DY-Ubuntu-01 ~]#docker run -d --name nginx7 -p 8088:80/tcp -p 8443:443/tcp -p 53:53/udp nginx
#一次性映射多个端口+协议

10、查看容器的日志

[root@DY-Ubuntu-01 ~]#docker logs mysql                    #查看日志
[root@DY-Ubuntu-01 ~]#docker logs --tail 3 mysql #查看最后三行日志
[root@DY-Ubuntu-01 ~]#docker logs --tail 3 -t mysql #显示时间
[root@DY-Ubuntu-01 ~]#docker logs -f mysql #持续跟踪日志

11、传递运行命令

[root@DY-Ubuntu-01 ~]#docker run -d alpine tail -f /etc/hosts    

12、容器内部的hosts文件

容器会自动将容器的ID加入自已的/etc/hosts文件中,并解析成容器的IP

[root@DY-Ubuntu-01 ~]#docker run -it --rm --add-host www.wang.org:6.6.6.6 --add-host www.dayu.org:8.8.8.8 busybox     #修改容器的 hosts文件

13、指定容器DNS

容器的dns服务器,默认采用宿主机的dns 地址,可以用下面方式指定其它的DNS地址
- 将dns地址配置在宿主机
- 在容器启动时加选项 --dns=x.x.x.x
- 在/etc/docker/daemon.json 文件中指定

#容器的DNS默认从宿主机的DNS获取
[root@DY-Ubuntu-01 ~]#systemd-resolve --status | grep -A1 -i "DNS server"
Current DNS Server: 192.168.100.1
DNS Servers: 192.168.100.1
[root@DY-Ubuntu-01 ~]#docker run -it --rm --name centos1 centos
[root@019dd9a4ba35 /]# egrep -v "^#|^$" /etc/resolv.conf
nameserver 192.168.100.1

#指定DNS地址
[root@DY-Ubuntu-01 ~]#docker run -it --rm --name centos2 --dns 1.1.1.1 --dns 6.6.6.6 --dns 8.8.8.8 centos bash
[root@d7ddcff827ba /]# egrep -v "^#|^$" /etc/resolv.conf
nameserver 1.1.1.1
nameserver 6.6.6.6
nameserver 8.8.8.8

#指定domain名
[root@DY-Ubuntu-01 ~]#docker run -it --rm --name centos3 --dns 6.6.6.6 --dns 8.8.8.8 --dns-searc wang.org --dns-search wang.com busybox
/ # egrep -v "^#|^$" /etc/resolv.conf
search wang.org wang.com
nameserver 6.6.6.6
nameserver 8.8.8.8

#配置文件指定DNS和搜索domain名
[root@DY-Ubuntu-01 ~]#vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://pgavrk5n.mirror.aliyuncs.com"],
"storage-driver": "overlay2",
"dns" : [ "114.114.114.114", "119.29.29.29"],
"dns-search": [ "wangxiaochun.com", "wang.org"]
}
[root@DY-Ubuntu-01 ~]#docker run -it --rm centos bash
[root@f35bfa417d29 /]# cat /etc/resolv.conf
search wangxiaochun.com wang.org
nameserver 114.114.114.114
nameserver 119.29.29.29

#用--dns指定优先级更高
[root@DY-Ubuntu-01 ~]#docker run -it --rm --dns 6.6.6.6 --dns 8.8.8.8 centos bash
[root@c6c43766b04e /]# cat /etc/resolv.conf
search wangxiaochun.com wang.org
nameserver 6.6.6.6
nameserver 8.8.8.8

14、容器内和宿主机之间复制文件

# 复制容器的文件至宿主机
[root@DY-Ubuntu-01 ~]#docker run -it --name b1 -d busybox sh
[root@DY-Ubuntu-01 ~]#docker cp b1:/bin/busybox /usr/local/bin/
[root@DY-Ubuntu-01 ~]#busybox ls

##将容器内文件复制到宿主机
[root@DY-Ubuntu-01 ~]#docker cp -a 5a44:/etc/centos-release .
[root@DY-Ubuntu-01 ~]#cat centos-release
CentOS Linux release 8.4.2105

#将宿主机文件复制到容器内
[root@DY-Ubuntu-01 ~]#docker cp /etc/issue 5a44:/root/
[root@DY-Ubuntu-01 ~]#docker exec 5a44 cat /root/issue
Ubuntu 20.04.4 LTS \n \l

15、使用 systemd 控制容器运行

[root@DY-Ubuntu-01 ~]#vim /lib/systemd/system/docker.service
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service
Wants=network-online.target

[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd -H unix://var/run/docker.sock
ExecReload=/bin/kill -s HUP $MAINPID
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
# Uncomment TasksMax if your systemd version supports it.
# Only systemd 226 and above support this version.
#TasksMax=infinity
TimeoutStartSec=0
# set delegate yes so that systemd does not reset the cgroups of docker containers
Delegate=yes
# kill only the docker process, not all processes in the cgroup
KillMode=process
# restart the docker process if it exits prematurely
Restart=on-failure
StartLimitBurst=3
StartLimitInterval=60s

[Install]
WantedBy=multi-user.target

[root@DY-Ubuntu-01 ~]#systemctl daemon-reload
[root@DY-Ubuntu-01 ~]#systemctl enable --now docker.service

16、 传递环境变量

有些容器运行时,需要传递变量,可以使用 -e <参数> 或 --env-file <参数文件> 实现

  • 传递变量创建MySQL

[root@DY-Ubuntu-01 ~]#docker run --name mysql1 -v /data/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_DATABASE=wordpress -e MYSQL_USER=wpuser -e MYSQL_PASSWORD=123456 -d -p 3306:3306 mysql:5.7.30

[root@DY-Ubuntu-01 ~]#vim env.list
MYSQL_ROOT_PASSWORD=123456
MYSQL_DATABASE=wordpress
MYSQL_USER=wpuser
MYSQL_PASSWORD=wppass
[root@DY-Ubuntu-01 ~]#docker run --name mysql2 -v /root/mysql/:/etc/mysql/conf.d -v /data/mysql2/:/var/lib/mysql --env-file=env.list -d -p 3308:3306 mysql:5.7.30

17、清除不再使用的数据

#dangling images表示TAG为<none>的镜像
[root@DY-Ubuntu-01 ~]#docker system prune
WARNING! This will remove:
- all stopped containers
- all networks not used by at least one container
- all dangling images
- all dangling build cache

Are you sure you want to continue? [y/N] y
Total reclaimed space: 0B

[root@DY-Ubuntu-01 ~]#docker system prune -f -a #清除不再使用的镜像

三、Docker 镜像制作和管理
1、制作镜像方式
  • Docker 镜像制作类似于虚拟机的镜像(模版)制作,即按照公司的实际业务需求将需要安装的软件、相关配置等基础环境配置完成,然后将其做成镜像,最后再批量从镜像批量生成容器实例,这样可以极大的简化相同环境的部署工作
  • Docker的镜像制作分为手动制作(基于容器)和自动制作(基于DockerFile),企业通常都是基于Dockerfile制作镜像

docker commit        #通过修改现有容器,将之手动构建为镜像
docker build #通过Dockerfile文件,批量构建为镜像

2、基于容器手动制作镜像步骤
2-1、docker commit 格式

docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

#选项
-a, --author string Author (e.g., "John Hannibal Smith <hannibal@a-team.com>")
-c, --change list Apply Dockerfile instruction to the created image
-m, --message string Commit message
-p, --pause Pause container during commit (default true)

#说明:
制作镜像和CONTAINER状态无关,停止状态也可以制作镜像
如果没有指定[REPOSITORY[:TAG]],REPOSITORY和TAG都为<none>
提交的时候标记TAG号: 生产当中常用,后期可以根据TAG标记创建不同版本的镜像以及创建不同版本的容器

基于容器手动制作镜像步骤具体如下:
1. 下载一个系统的官方基础镜像,如: CentOS 或 Ubuntu
2. 基于基础镜像启动一个容器,并进入到容器
3. 在容器里面做配置操作
- 安装基础命令
- 配置运行环境
- 安装服务和配置服务
- 放业务程序代码
4. 提交为一个新镜像 docker commit
5. 基于自己的的镜像创建容器并测试访问

2-2、基于 busybox 制作 httpd 镜像

[root@DY-Ubuntu-01 ~]#docker run -it --name b1 busybox
/ # mkdir /data/html -p
/ # echo httpd website in busybox > /data/html/index.html
/ # exit

#格式一:
[root@DY-Ubuntu-01 ~]#docker commit -a "wang<root@wangdayu.com>" -c 'CMD /bin/httpd -fv -h /data/html' -c "EXPOSE 80" b1 httpd-busybox:v1.0
#格式二:
[root@DY-Ubuntu-01 ~]#docker commit -a "wwww.wang.org" -c 'CMD ["/bin/httpd","-f","-v","-h","/data/html"]' -c "EXPOSE 80" b1 httpd-busybox:v1.1


[root@DY-Ubuntu-01 ~]#docker run -d -P --name httpd1 httpd-busybox:v1.0
f0c8b6baed03e1cd882ff25b0ecbd1d43d1ab03d4f0bc6bacb9dd12e0b4155be
[root@DY-Ubuntu-01 ~]#docker port httpd1
80/tcp -> 0.0.0.0:49153
80/tcp -> :::49153
[root@DY-Ubuntu-01 ~]#docker inspect -f "{{.NetworkSettings.Networks.bridge.IPAddress}}" httpd1
172.17.0.4

[root@DY-Ubuntu-01 ~]#docker exec -it httpd1 sh
/ # pstree -p
httpd(1)
/ # ps aux
PID USER TIME COMMAND
1 root 0:00 /bin/httpd -fv -h /data/html
7 root 0:00 sh
15 root 0:00 ps aux
/ # exit

[root@DY-Ubuntu-01 ~]#curl 172.17.0.4
httpd website in busybox

[root@DY-Ubuntu-01 ~]#curl 127.1:49153
httpd website in busybox

2-3、基于官方镜像生成的容器制作 tomcat 镜像

[root@DY-Ubuntu-01 ~]#docker run -d -p 8080:8080 tomcat     
[root@DY-Ubuntu-01 ~]#docker ps
[root@DY-Ubuntu-01 ~]#docker exec -it 4a7c3c2e0b8d bash
root@4a7c3c2e0b8d:/usr/local/tomcat# cp -a webapps.dist/* webapps/
[root@DY-Ubuntu-01 ~]#docker commit -m "add webapps app" -a "www.wang.org" 4a7c3c2e0b8d tomcat:9.0.0-v1.0
[root@DY-Ubuntu-01 ~]#docker history tomcat:9.0.0-v1.0
[root@DY-Ubuntu-01 ~]#docker inspect tomcat:9.0.0-v1.0 | tail -n20 #查看创建时间
[root@DY-Ubuntu-01 ~]#docker rm -f 4a7c3c2e0b8d #删除当前的容器
4a7c3c2e0b8d
[root@DY-Ubuntu-01 ~]#docker run -d -p 8080:8080 --name tomcat tomcat:9.0.0-v1.0
浏览器访问http://192.168.100.201:8080/即可

2-4、基于Ubuntu的基础镜像利用 apt 安装手动制作nginx 的镜像

[root@DY-Ubuntu-01 ~]#docker run -it -p 80 --name nginx_ubuntu ubuntu bash
root@052fcea2d7d0:/# cat > /etc/apt/sources.list
deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse

root@052fcea2d7d0:/# apt update
root@052fcea2d7d0:/# apt install -y nginx
#注意,运行一半会提示配置时区,如果不配置会一直卡在此处,先输入6选择Asia,再选择70上海,如下:
......
1. Africa 3. Antarctica 5. Arctic 7. Atlantic 9. Indian 11. SystemV 13. Etc
2. America 4. Australia 6. Asia 8. Europe 10. Pacific 12. US
Geographic area: 6 #选择Asia,输入6

1. Aden 19. Chongqing 37. Jerusalem 55. Novokuznetsk 73. Taipei
2. Almaty 20. Colombo 38. Kabul 56. Novosibirsk 74. Tashkent
3. Amman 21. Damascus 39. Kamchatka 57. Omsk 75. Tbilisi
4. Anadyr 22. Dhaka 40. Karachi 58. Oral 76. Tehran
5. Aqtau 23. Dili 41. Kashgar 59. Phnom_Penh 77. Tel_Aviv
6. Aqtobe 24. Dubai 42. Kathmandu 60. Pontianak 78. Thimphu
7. Ashgabat 25. Dushanbe 43. Khandyga 61. Pyongyang 79. Tokyo
8. Atyrau 26. Famagusta 44. Kolkata 62. Qatar 80. Tomsk
9. Baghdad 27. Gaza 45. Krasnoyarsk 63. Qostanay 81. Ujung_Pandang
10. Bahrain 28. Harbin 46. Kuala_Lumpur 64. Qyzylorda 82. Ulaanbaatar
11. Baku 29. Hebron 47. Kuching 65. Rangoon 83. Urumqi
12. Bangkok 30. Ho_Chi_Minh 48. Kuwait 66. Riyadh 84. Ust-Nera
13. Barnaul 31. Hong_Kong 49. Macau 67. Sakhalin 85. Vientiane
14. Beirut 32. Hovd 50. Magadan 68. Samarkand 86. Vladivostok
15. Bishkek 33. Irkutsk 51. Makassar 69. Seoul 87. Yakutsk
16. Brunei 34. Istanbul 52. Manila 70. Shanghai 88. Yangon
17. Chita 35. Jakarta 53. Muscat 71. Singapore 89. Yekaterinburg
18. Choibalsan 36. Jayapura 54. Nicosia 72. Srednekolymsk 90. Yerevan

Time zone: 70 #选择上海,输入70
......

root@ea56415c5e2f:/# nginx -v
nginx version: nginx/1.18.0 (Ubuntu)
root@ea56415c5e2f:/# echo "Nginx website in Docker" > /var/www/html/index.html
root@ea56415c5e2f:/# exit

[root@DY-Ubuntu-01 ~]#docker commit -a "www.wang.org" -m 'nginx-ubuntu:20.04' nginx_ubuntu nginx_ubuntu2004:v1.18

[root@DY-Ubuntu-01 ~]#docker run -it -d -p 80 --name nginx-web nginx_ubuntu2004:v1.18 nginx -g 'daemon off;'
[root@DY-Ubuntu-01 ~]#docker port nginx-web
80/tcp -> 0.0.0.0:49156
80/tcp -> :::49156
[root@DY-Ubuntu-01 ~]#curl http://127.0.0.1:49156
Nginx website in Docker

2-5、基于CentOS的基础镜像利用 yum 安装手动制作nginx 的镜像

[root@DY-Ubuntu-01 ~]#docker pull centos

[root@a1c6b31020f6 /]# rm -rf /etc/localtime
[root@a1c6b31020f6 /]# ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
[root@a1c6b31020f6 /]# cd /etc/yum.repos.d/
[root@a1c6b31020f6 yum.repos.d]# mkdir backup
[root@a1c6b31020f6 yum.repos.d]# mv *.repo backup/
[root@a1c6b31020f6 yum.repos.d]# vim base.repo #需改为yum源
[BaseOS]
name=BaseOS
baseurl=https://mirrors.aliyun.com/centos/$releasever/BaseOS/$basearch/os/
gpgcheck=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial

[AppStream]
name=AppStream
baseurl=https://mirrors.aliyun.com/centos/$releasever/AppStream/$basearch/os/
gpgcheck=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial

[extras]
name=extras
baseurl=https://mirrors.aliyun.com/centos/$releasever/extras/$basearch/os/
gpgcheck=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
enabled=1

[epel]
name=epel
baseurl=https://mirrors.aliyun.com/epel/$releasever/Everything/$basearch/
gpgcheck=0
gpgkey=https://mirrors.aliyun.com/epel/RPM-GPG-KEY-EPEL-\$releasever

[root@a1c6b31020f6 yum.repos.d]# yum makecache
[root@a1c6b31020f6 yum.repos.d]# yum -y install wget

[root@a1c6b31020f6 ~]# yum install -y nginx #安装nginx
[root@a1c6b31020f6 ~]# yum install -y vim curl iproute net-tools #安装常用命令
[root@a1c6b31020f6 ~]# rm -rf /var/cache/yum ##清理yum缓存

[root@a1c6b31020f6 ~]# vim /etc/nginx/nginx.conf #关闭nginx后台运行
user nginx;
daemon off;

[root@a1c6b31020f6 ~]# rm -r /usr/share/nginx/html/index.html
rm: remove regular file '/usr/share/nginx/html/index.html'? y
[root@a1c6b31020f6 ~]# echo "Nginx Page in Docker" > /usr/share/nginx/html/index.html #自定义web界面

#不要退出容器,在另一个终端窗口执行以下命令
[root@DY-Ubuntu-01 ~]#docker commit -a "www.wang.org" -m "nginx-v1" -c "EXPOSE 80 443" a1c6b31020f6 centos_nginx:1.18.v1 #docker commit 命令在宿主机基于容器ID 提交为镜像

#从制作的镜像启动容器
[root@DY-Ubuntu-01 ~]#docker run -d -p 8080:80 --name my-nginx centos_nginx:1.18.v1 /usr/sbin/nginx

[root@DY-Ubuntu-01 ~]#curl 127.1:8080 #访问测试镜像
Nginx Page in Docker

2-6、基于CentOS 基础镜像手动制作编译版本 nginx 镜像

[root@docker ~]#docker pull centos
[root@docker ~]#docker run -it --name centos_nginx centos /bin/bash
[root@4ab9cc8c4c8b /]# cd /etc/yum.repos.d/
[root@4ab9cc8c4c8b yum.repos.d]# mkdir back
[root@4ab9cc8c4c8b yum.repos.d]# mv *.repo back

[root@4ab9cc8c4c8b yum.repos.d]# vi base.repo

[BaseOS]
name=BaseOS
baseurl=https://mirrors.aliyun.com/centos/$releasever/BaseOS/$basearch/os/
gpgcheck=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial

[AppStream]
name=AppStream
baseurl=https://mirrors.aliyun.com/centos/$releasever/AppStream/$basearch/os/
gpgcheck=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial

[extras]
name=extras
baseurl=https://mirrors.aliyun.com/centos/$releasever/extras/$basearch/os/
gpgcheck=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
enabled=1

[epel]
name=epel
baseurl=https://mirrors.aliyun.com/epel/$releasever/Everything/$basearch/
gpgcheck=0
gpgkey=https://mirrors.aliyun.com/epel/RPM-GPG-KEY-EPEL-\$releasever

[root@4ab9cc8c4c8b ~]# cd
[root@4ab9cc8c4c8b ~]# useradd -r -s /sbin/nologin nginx
[root@4ab9cc8c4c8b ~]# yum -y install gcc gcc-c++ automake pcre pcre-devel zlib zlib-devel openssl openssl-devel make
[root@4ab9cc8c4c8b ~]# cd /usr/local/src/
[root@4ab9cc8c4c8b src]# wget http://nginx.org/download/nginx-1.23.1.tar.gz
[root@4ab9cc8c4c8b src]# tar xf nginx-1.23.1.tar.gz
[root@4ab9cc8c4c8b src]# cd nginx-1.23.1
[root@4ab9cc8c4c8b nginx-1.23.1]# ./configure --prefix=/apps/nginx
[root@4ab9cc8c4c8b nginx-1.23.1]# make && make install
[root@4ab9cc8c4c8b nginx-1.23.1]# rm -rf nginx*
[root@4ab9cc8c4c8b nginx-1.23.1]# rm -rf /var/cache/yum/*
[root@4ab9cc8c4c8b nginx-1.23.1]# cd /apps/nginx
[root@4ab9cc8c4c8b nginx]# ls
conf html logs sbin
[root@4ab9cc8c4c8b nginx]# vi conf/nginx.conf
user nginx;
daemon off;
[root@4ab9cc8c4c8b nginx]# ln -s /apps/nginx/sbin/nginx /usr/sbin/
[root@4ab9cc8c4c8b nginx]# ls /usr/sbin/nginx
/usr/sbin/nginx

#自定义web界面
[root@4ab9cc8c4c8b nginx]# echo "Nginx test page in docker" > /apps/nginx/html/index.html


#提交为镜像
#不要退出容器,在另一个终端窗口执行以下命令
[root@docker ~]#docker commit -a "www.wang.org" -m "nginx" -c "CMD nginx" 4ab9cc8c4c8b centos_nginx:v1.18

# 从自己的镜像启动容器
[root@docker ~]#docker run -d -p 80:80 centos_nginx:v1.18 nginx
备注: 最后面的nginx是运行的命令,即镜像里面要运行一个nginx命令,所以前面软链接到/usr/sbin/nginx,目的为了让系统不需要指定路径就可以执行此命令

#访问测试
[root@docker ~]#curl 127.0.0.1
Nginx test page in docke

#查看Nginx访问日志和进程
[root@docker ~]#docker exec -it a2c34e803eb3 /bin/bash
[root@a2c34e803eb3 /]# cat /apps/nginx/logs/access.log
172.17.0.1 - - [16/Oct/2022:12:26:05 +0000] "GET / HTTP/1.1" 200 26 "-" "curl/7.68.0"
[root@a2c34e803eb3 /]# exit

3、docker build基于dockerfile文件构建镜像

Dockerfile 介绍

DockerFile 是一种被Docker程序解释执行的脚本,由一条条的命令组成的,每条命令对应linux下面的一条命令,Docker程序将这些DockerFile指令再翻译成真正的linux命令,其有自己的书写方式和支持的命令,Docker程序读取DockerFile并根据指令生成Docker镜像,相比手动制作镜像的方式,DockerFile更能直观的展示镜像是怎么产生的,有了DockerFile,当后期有额外的需求时,只要在之前的DockerFile添加或者修改相应的命令即可重新生成新的Docker镜像,避免了重复手动制作镜像的麻烦,类
似与shell脚本一样,可以方便高效的制作镜像
Docker守护程序 Dockerfile 逐一运行指令,如有必要,将每个指令的结果提交到新镜像,然后最终输出新镜像的ID。Docker守护程序将自动清理之前发送的上下文
注意,每条指令都是独立运行的,并会导致创建新镜像,比如 RUN cd /tmp 对下一条指令不会有任何影响。
Docker将尽可能重用中间镜像层(缓存),以显著加速 docker build 命令的执行过程,这由 Using cache 控制台输出中的消息指示

Dockerfile 文件格式

Dockerfile 是一个有特定语法格式的文本文件 dockerfile 官方说明: ​​https://docs.docker.com/engine/reference/builder/​​ 帮助: man 5 dockerfile

Dockerfile 文件说明

  • 每一行以Dockerfile的指令开头,指令不区分大小写,但是惯例使用大写
  • 使用 # 开始作为注释
  • 每一行只支持一条指令,每条指令可以携带多个参数
  • 指令按文件的顺序从上至下进行执行
  • 每个指令的执行会生成一个新的镜像层,为了减少分层和镜像大小,尽可能将多条指令合并成一条指令
  • 制作镜像一般可能需要反复多次,每次执行dockfile都按顺序执行,从头开始,已经执行过的指令已经缓存,不需要再执行,如果后续有一行新的指令没执行过,其往后的指令将会重新执行,所以为加速镜像制作,将最常变化的内容放下dockerfile的文件的后面

Dockerfile 相关指令

#dockerfile 文件中的常见指令
FROM
LABEL
ENV
RUN
CMD
ADD
COPY
ENTRYPOINT
EXPOSE
WORKDIR
USER
VOLUME
STOPSIGNAL

Docker从入门到精通_docker

3-1、FROM: 指定基础镜像

定制镜像,需要先有一个基础镜像,在这个基础镜像上进行定制。
FROM 就是指定基础镜像,此指令通常必需放在Dockerfile文件第一个非注释行。后续的指令都是运行于此基准镜像所提供的运行环境
基础镜像可以是任何可用镜像文件,默认情况下,docker build会在docker主机上查找指定的镜像文件,在其不存在时,则会从Docker Hub Registry上拉取所需的镜像文件.如果找不到指定的镜像文件,docker build会返回一个错误信息

FROM [--platform=<platform>] <image> [AS <name>]
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]
#说明:
--platform 指定镜像的平台,比如: linux/amd64, linux/arm64, or windows/amd64 tag 和 digest是可选项,如果不指定,默认为latest

关于scratch 镜像

FROM scratch
参考链接:
https://hub.docker.com/_/scratch?tab=description
https://docs.docker.com/develop/develop-images/baseimages/
该镜像是一个空的镜像,可以用于构建busybox等超小镜像,可以说是真正的从零开始构建属于自己的镜像,该镜像在构建基础镜像(例如debian和busybox)或超最小镜像(仅包含一个二进制文件及其所需内容,例如:hello-world)的上下文中最有用

3-2、 LABEL: 指定镜像元数据

可以指定镜像元数据,如: 镜像作者等
LABEL <key>=<value> <key>=<value> <key>=<value> ...

一个镜像可以有多个label ,还可以写在一行中,即多标签写法,可以减少镜像的的大小
#一行格式
LABEL multi.label1="value1" multi.label2="value2" other="value3"
#多行格式
LABEL multi.label1="value1" \
multi.label2="value2" \
other="value3"

MAINTAINER: 指定维护者信息
此指令已过时,用LABEL代替

3-3、RUN: 执行 shell命令

- RUN 指令用来在构建镜像阶段需要执行 FROM 指定镜像所支持的Shell命令。
- 通常各种基础镜像一般都支持丰富的shell命令
- 注意: RUN 可以写多个,每一个RUN指令都会建立一个镜像层,所以尽可能合并成一条指令,比如将多个shell命令通过 && 连接一起成为在一条指令
- 每个RUN都是独立运行的,和前一个RUN无关

#shell 格式: 相当于 /bin/sh -c <命令> 此种形式支持环境变量
RUN <命令>

#exec 格式: 此种形式不支持环境变量,注意:是双引号,不能是单引号
RUN ["executable","param1","param2"...]

#exec格式可以指定其它shell
RUN ["/bin/bash","-c","echo hello wang"]

shell格式中,<command>通常是一个shell命令,且以"/bin/sh -c”来运行它,这意味着此进程在容器中的PID不为1,不能接收Unix信号,因此,当使用docker stop <container>命令停止容器时,此进程接收不到SIGTERM信号

exec格式中的参数是一个JSON格式的数组,其中<executable>为要运行的命令,后面的<paramN>为传递给命令的选项或参数;然而,此种格式指定的命令不会以"/bin/sh -c"来发起,因此常见的shell操作如变量替换以及通配符(?,*等)替换将不会进行;不过,如果要运行的命令依赖于此shell特性的话,可以将其替换为类似下面的格式。
RUN ["/bin/bash", "-c", "<executable>", "<param1>"]

3-4、ENV: 设置环境变量

ENV 可以定义环境变量和值,会被后续指令(如:ENV,ADD,COPY,RUN等)通过{KEY}进行引用,并在容器运行时保持

#变量赋值格式1
ENV <key> <value> #此格式只能对一个key赋值,<key>之后的所有内容均会被视作其<value>的组成
部分

#变量赋值格式2
ENV <key1>=<value1> <key2>=<value2> \ #此格式可以支持多个key赋值,定义多个变量建议使用,
减少镜像层
<key3>=<value3> ...

#如果<value>中包含空格,可以以反斜线\进行转义,也可通过对<value>加引号进行标识;另外,反斜线也可用于续行

#只使用一次变量
RUN <key>=<value> <command>

#引用变量
RUN $key .....

#变量支持高级赋值格式
${key:-word}
${kye:+word}

如果运行容器时如果需要修改变量,可以执行下面通过基于 exec 机制实现 注意: 下面方式只影响容器运行时环境,而不影响构建镜像的过程,即只能覆盖docker run时的环境变量,而不会影响docker build时环境变量的值

docker run -e|--env <key>=<value>
#说明
-e, --env list #Set environment variables
--env-file filename #Read in a file of environment variables

#格式1
ENV myName="John Doe" myDog=Rex\ The\ Dog \
myCat=fluffy
#格式2
ENV myName John Doe
ENV myDog Rex The Dog
ENV myCat fluffy

3-5、COPY: 复制文本

复制本地宿主机的 到容器中的

COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"] #路径中有空白字符时,建议使用此格式

说明:

  • 可以是多个,可以使用通配符,通配符规则满足Go的filepath.Match 规则
  • filepath.Match 参考链接:​​https://golang.org/pkg/path/filepath/#Match​​
  • 必须是build上下文中的路径(为 Dockerfile 所在目录的相对路径),不能是其父目录中的文件
  • 如果是目录,则其内部文件或子目录会被递归复制,但目录自身不会被复制
  • 如果指定了多个, 或使用了通配符,则必须是一个目 录,且必须以 / 结尾
  • 可以是绝对路径或者是 WORKDIR 指定的相对路径
  • 使用 COPY 指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等
  • 如果事先不存在,它将会被自动创建,这包括其父目录路径,即递归创建目录
3-6、ADD: 复制和解包文件

该命令可认为是增强版的COPY,不仅支持COPY,还支持自动解压缩。可以将其复制到容器中指定的路径

ADD [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]

说明:

  • 可以是Dockerfile所在目录的一个相对路径;也可是一个 URL;还可是一个 tar 文件(自动解压)
  • 可以是绝对路径或者是 WORKDIR 指定的相对路径
  • 如果是目录,只复制目录中的内容,而非目录本身
  • 如果是一个 URL ,下载后的文件权限自动设置为 600
  • 如果为URL且不以/结尾,则指定的文件将被下载并直接被创建为,如果以 / 结尾,则文件名URL指定的文件将被直接下载并保存为/< filename>
  • 如果是一个本地文件系统上的打包文件,如: gz, bz2 ,xz ,它将被解包 ,其行为类似于"tar -x"命令,但是通过URL获取到的tar文件将不会自动展开
  • 如果有多个,或其间接或直接使用了通配符,则必须是一个以/结尾的目录路径;如果不以/结尾,则其被视作一个普通文件,的内容将被直接写入到
3-7、CMD: 容器启动命令

一个容器中需要持续运行的进程一般只有一个,CMD 用来指定启动容器时默认执行的一个命令,且其运行结束后,容器也会停止,所以一般CMD 指定的命令为持续运行且为前台命令.
- 如果docker run没有指定任何的执行命令或者dockerfile里面也没有ENTRYPOINT命令,那么开启容器时就会使用执行CMD指定的默认的命令
- 前面介绍过的 RUN 命令是在构建镜像时执行的命令,注意二者的不同之处
- 每个 Dockerfile 只能有一条 CMD 命令。如指定了多条,只有最后一条被执行
- 如果用户启动容器时用 docker run xxx 指定运行的命令,则会覆盖 CMD 指定的命令

# 使用 exec 执行,推荐方式,第一个参数必须是命令的全路径,此种形式不支持环境变量
CMD ["executable","param1","param2"]
# 在 /bin/sh 中执行,提供给需要交互的应用;此种形式支持环境变量
CMD command param1 param2
# 提供给 ENTRYPOINT 命令的默认参数
CMD ["param1","param2"]

3-8、ENTRYPOINT: 入口点

功能类似于CMD,配置容器启动后执行的命令及参数

# 使用 exec 执行
ENTRYPOINT ["executable", "param1", "param2"...]
# shell中执行
ENTRYPOINT command param1 param2

  • ENTRYPOINT 不能被 docker run 提供的参数覆盖,而是追加,即如果docker run 命令有参数,那么参数全部都会作为ENTRYPOINT的参数
  • 如果docker run 后面没有额外参数,但是dockerfile中有CMD命令(即上面CMD的第三种用法),即Dockerfile中即有CMD也有ENTRYPOINT,那么CMD的全部内容会作为ENTRYPOINT的参数
  • 如果docker run 后面有额外参数,同时Dockerfile中即有CMD也有ENTRYPOINT,那么docker run后面的参数覆盖掉CMD参数内容,最终作为ENTRYPOINT的参数
  • 可以通过docker run --entrypoint string 参数在运行时替换,注意string不要加空格
  • 使用CMD要在运行时重新写命令本身,然后在后面才能追加运行参数,ENTRYPOINT则可以运行时无需重写命令就可以直接接受新参数
  • 每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个生效
  • 通常会利用ENTRYPOINT指令配合脚本,可以为CMD指令提供环境配置
3-9、ARG: 构建参数

ARG指令在build 阶段指定变量,和ENV不同的是,容器运行时不会存在这些环境变量

ARG <name>[=<default value>]

如果和ENV同名,ENV覆盖ARG变量 可以用 docker build --build-arg <参数名>=<值> 来覆盖

说明: ARG 和 FROM

#FROM指令支持ARG指令放在第一个FROM之前声明变量
#示例:
ARG CODE_VERSION=latest
FROM base:${CODE_VERSION}
CMD /code/run-app
FROM extras:${CODE_VERSION}
CMD /code/run-extras
#在FROM之前声明的ARG在构建阶段之外,所以它不能在FROM之后的任何指令中使用。 要使用在第一个FROM
之前声明的ARG的默认值,请在构建阶段内使用没有值的ARG指令
#示例:
ARG VERSION=latest
FROM busybox:$VERSION
ARG VERSION
RUN echo $VERSION > image_version

3-10、VOLUME: 匿名卷

在容器中创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等,默认会将宿主机上的目录挂载至VOLUME 指令指定的容器目录。即使容器后期被删除,此宿主机的目录仍会保留,从而实现容器数据的持久保存。

宿主机目录为

/var/lib/docker/volumes/<volume_id>/_data

VOLUME <容器内路径>
VOLUME ["<容器内路径1>", "<容器内路径2>"...]

注意:
<容器内路径>如果在容器内不存在,在创建容器时会自动创建
<容器内路径>如果是存在的,同时目录内有内容,将会把此目录的内容复制到宿主机的实际目录

注意:

  • Dockerfile中的VOLUME实现的是匿名数据卷,无法指定宿主机路径和容器目录的挂载关系
  • 通过docker rm -fv <容器ID> 可以删除容器的同时删除VOLUME指定的卷
3-11、EXPOSE: 暴露端口

指定服务端的容器需要对外暴露(监听)的端口号,以实现容器与外部通信。

EXPOSE 仅仅是声明容器打算使用什么端口而已,并不会真正暴露端口,即不会自动在宿主进行端口映射,因此,在启动容器时需要通过 -P 或 -p ,Docker 主机才会真正分配一个端口转发到指定暴露的端口才可使用

注意: 即使 Dockerfile 没有 EXPOSE 端口指令,也可以通过docker run -p 临时暴露容器内程序真正监听的端口,所以EXPOSE 相当于指定默认的暴露端口,可以通过docker run -P 进行真正暴露

EXPOSE <port>[/ <protocol>] [<port>[/ <protocol>] ..]
#说明
<protocol>用于指定传输层协议,可为tcp或udp二者之一,默认为TCP协

EXPOSE 80 443
EXPOSE 11211/udp 11211/tcp

3-12、WORKDIR: 指定工作目录

为后续的 RUN、CMD、ENTRYPOINT 指令配置工作目录,当容器运行后,进入容器内WORKDIR指定的默认目录

WORKDIR 指定工作目录(或称当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会自行创建

WORKDIR /path/to/workdir

3-13、ONBUILD: 子镜像引用父镜像的指令

可以用来配置构建当前镜像的子镜像时,自动触发执行的指令,但在当前镜像构建时,并不会执行,即延迟到子镜像构建时才执行

ONBUILD [INSTRUCTION]

说明:

  • 尽管任何指令都可注册成为触发器指令,但ONBUILD不能自我能套,且不会触发FROM和MAINTAINER指令
  • 使用 ONBUILD 指令的镜像,推荐在标签中注明,例如 ruby:1.9-onbuild
3-14、USER: 指定当前用户

指定运行容器的用户名或 UID,在后续dockerfile中的 RUN ,CMD和ENTRYPOINT指令时使用此用户

当服务不需要管理员权限时,可以通过该命令指定运行用户

这个用户必须是事先建立好的,否则无法切换

如果没有指定 USER,默认是 root 身份执行

USER <user>[:<group>]
USER <UID>[:<GID>]

3-15、HEALTHCHECK: 健康检查

检查容器的健康性

HEALTHCHECK [选项] CMD <命令>    #设置检查容器健康状况的命令,如果命令执行失败,则返回1,即unhealthy
HEALTHCHECK NONE #如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令

HEALTHCHECK 支持下列选项:
--interval=<间隔> #两次健康检查的间隔,默认为 30 秒
--timeout=<时长> #健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认 30 秒
--retries=<次数> #当连续失败指定次数后,则将容器状态视为 unhealthy,默认3次
--start-period=<FDURATION> #default: 0s

#检查结果返回值:
0 #success the container is healthy and ready for use
1 #unhealthy the container is not working correctly
2 #reserved do not use this exit code

3-16、dockerignore文件

官方文档: ​​https://docs.docker.com/engine/reference/builder/#dockerignore-file​​

与.gitignore文件类似,生成构建上下文时Docker客户端应忽略的文件和文件夹指定模式

.dockerignore 使用 Go 的文件路径规则 filepath.Match

参考链接: ​​https://golang.org/pkg/path/filepath/#Match​​

完整的语法

#     #以#开头的行为注释
* #匹配任何非分隔符字符序列
? #匹配任何单个非分隔符
\\ #表示 \
** #匹配任意数量的目录(包括零)例如,**/*.go将排除在所有目录中以.go结尾的所有文件,包括构建上下文的根。
! #表示取反,可用于排除例外情况

#排除 test 目录下的所有文件
test/*
#排除 md 目录下的 xttblog.md 文件
md/xttblog.md
#排除 xttblog 目录下的所有 .md 的文件
xttblog/*.md
#排除以 xttblog 为前缀的文件和文件夹
xttblog?
#排除所有目录下的 .sql 文件夹
**/*.sql

3-17、Dockerfile 构建过程和指令总结

Dockerfile 构建过程

  • 从基础镜像运行一个容器
  • 执行一条指令,对容器做出修改
  • 执行类似docker commit的操作,提交一个新的中间镜像层(可以利用中间层镜像创建容器进行调试和排错)
  • 再基于刚提交的镜像运行一个新容器
  • 执行Dockerfile中的下一条指令,直至所有指令执行完毕

Dockerfile 指令总结

BUILD

RUN

BOTH

FROM

CMD

WORKDIR

LABEL

VOLUME

USER

ADD

EXPOSE

ENV

COPY

ENTRYPOINT


RUN



ONBUILD



.dockerignore



3-18、构建镜像docker build 命令

docker build命令使用Dockerfile文件创建镜像

docker build [OPTIONS] PATH | URL | -
说明:
PATH | URL | - #可以使是本地路径,也可以是URL路径。若设置为 - ,则从标准输入获取
Dockerfile的内容
-f, --file string #Dockerfile文件名,默认为 PATH/Dockerfile
--force-rm #总是删除中间层容器,创建镜像失败时,删除临时容器
--no-cache #不使用之前构建中创建的缓存
-q --quiet=false #不显示Dockerfile的RUN运行的输出结果
--rm=true #创建镜像成功时,删除临时容器
-t --tag list #设置注册名称、镜像名称、标签。格式为 <注册名称>/<镜像名称>:<标签>(标签默认为latest)

查看镜像的构建历史:

docker history 镜像ID

四、docker build构建镜像案例
1、构建tomcat镜像并运行jpress

Docker从入门到精通_ubuntu_02

1-1、构建ubuntu基础详细

[root@node1 jdk]# cd /data/dockerfile/system/ubuntu/
[root@node1 ubuntu]# vim Dockerfile

FROM ubuntu:focal-20220922
LABEL maintainer="www.wang.org" version=ubuntu_dayu:v2.0
ENV name=wang

COPY sources.list /etc/apt/sources.list
RUN apt update && \
apt -y install tree wget vim curl iproute2 tzdata zip unzip && \
rm -f /etc/localtime && \
ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

[root@node1 ubuntu]# vim sources.list

deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse

# deb http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse
# deb-src http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse

[root@node1 ubuntu]# docker build -t ubuntu_dayu:v2.0 .

1-2、构建jdk镜像

[root@node1 ubuntu]# cd /data/dockerfile/app/jdk/
[root@node1 jdk]# vim Dockerfile

FROM ubuntu_dayu:v2.0
LABEL maintainer="www.wang.org" ver="ubuntu_jdk:v1.0"
ENV version=1.8.0_341

ADD jdk-8u341-linux-x64.tar.gz /usr/local/

RUN cd /usr/local/ && \
ln -s jdk${version}/ jdk && \
echo "export JAVA_HOME=/usr/local/jdk\nexport PATH=$PATH:/usr/local/jdk/bin" > /etc/profile.d/jdk.sh

ENV JAVA_HOME /usr/local/jdk
ENV PATH $PATH:${JAVA_HOME}/bin

[root@node1 jdk]# docker build -t ubuntu_jdk:v1.0 .

1-3、构建tomcat镜像

[root@node1 jdk]# cd /data/dockerfile/app/tomcat/
[root@node1 tomcat]# vim Dockerfile

FROM ubuntu_jdk:v1.0
LABEL maintainer="www.wang.org" version="ubuntu_tomcat:v1.0"
ENV version apache-tomcat-9.0.65

ADD ${version}.tar.gz /usr/local/

RUN cd /usr/local/ && \
ln -s ${version} tomcat

[root@node1 tomcat]# docker build -t ubuntu_tomcat:v1.0 .

[root@node1 tomcat]# docker run -it --rm ubuntu_tomcat:v1.0 bash #进入容器
root@688981e2a3b4:/# /usr/local/tomcat/bin/catalina.sh start #开启tomcat
root@688981e2a3b4:/# ss -ntlp #查看端口是否开启
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 1 127.0.0.1:8005 0.0.0.0:* users:(("java",pid=15,fd=65))
LISTEN 0 100 0.0.0.0:8080 0.0.0.0:* users:(("java",pid=15,fd=57))

[root@node1 tomcat]# curl 172.17.0.2:8080 #另开一终端,测试访问

1-4、构建jpress镜像

[root@node1 jpress]# vim Dockerfile
FROM ubuntu_tomcat:v1.0
LABEL maintainer="www.wang.org" version="ubuntu_jpress:v1.0"

COPY jpress-v5.0.2.war /data/jpress/
COPY server.xml /usr/local/tomcat/conf/server.xml
COPY run_tomcat.sh /usr/local/tomcat/bin/run_tomcat.sh

RUN cd /data/jpress && \
mv jpress-v5.0.2.war ROOT.war && \
groupadd -g 808 -r tomcat && \
useradd -u 808 -g tomcat -M -r tomcat && \
chown -R tomcat.tomcat /data/jpress

CMD ["/usr/local/tomcat/bin/run_tomcat.sh"]

[root@node1 jpress]# vim run_tomcat.sh
echo "nameserver 180.76.76.76" > /etc/resolv.conf
usr/local/tomcat/bin/catalina.sh start
tail -f /etc/hosts

[root@node1 jpress]# docker build -t ubuntu_jpress:v1.0 .

1-5、连接数据库

# 数据库服务器建立好用户名密码:
[root@DY-Ubuntu-03 ~]#vim /etc/mysql/mysql.conf.d/mysqld.cnf
[mysqld]
default_authentication_plugin=mysql_native_password
#bind-address = 127.0.0.1
#mysqlx-bind-address = 127.0.0.1
[root@DY-Ubuntu-03 ~]#systemctl restart mysql.service
[root@DY-Ubuntu-03 ~]#mysql
mysql> create database jpress;
mysql> create user jpress@'%' identified by '123456';
mysql> grant all on jpress.* to jpress@'%' ;

#浏览器输入容器宿主ip 192.168.100.102:8080 打开连接数据库即可

2、构建CentOS的nginx镜像

[root@node1 centos]# vim base.repo             #做yum模板
......

[root@node1 centos]# vim Dockerfile #编写dockerfile文件
FROM centos_dayu:v1.0
LABEL maintainer="www.wang.org" version="centos_nginx:v1.0"
ENV version="nginx-1.22.0" NGINX_INSTALL_DIR="/apps/nginx"

RUN rm -f /etc/yum.repos.d/*
ADD base.repo /etc/yum.repos.d/
RUN yum -y install make gcc-c++ libtool pcre pcre-devel zlib zlib-devel openssl openssl-devel perl-ExtUtils-Embed

ADD ${version}.tar.gz /usr/local/

RUN cd /usr/local/${version} && \
groupadd -g 88 -r nginx && \
useradd -u 88 -g nginx -M -r nginx && \
./configure --prefix=${NGINX_INSTALL_DIR} --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module && \
make && make install && \
rm -rf /usr/local/${version} && \
rm -rf /var/cache/dnf/*

EXPOSE 80
CMD ["/apps/nginx/sbin/nginx","-g","daemon off;"]
[root@node1 centos]# docker build -t centos_nginx:v1.0 . #构建镜像
[root@node1 centos]# docker run -it --rm -P centos_nginx:v1.1 #运行容器

[root@wdy software]#curl 192.168.100.102:49155 #测试访问

3、制作自定义tomcat业务镜像
1、构建系统基础镜像

[root@node1 ~]# docker pull centos
[root@node1 ~]# mkdir -p /data/dockerfile/{app/{nginx,tomcat,jdk},system/{centos,ubuntu,alpine,debian}}
[root@node1 ~]# cd /data/dockerfile/system/centos/
[root@node1 centos]# vim Dockerfile
FROM centos
LABEL maintainer="www.wang.org" version="centos_dayu_tomcat:v1.0"

RUN rm -f /etc/yum.repos.d/*
ADD base.repo /etc/yum.repos.d/
RUN yum -y install make tree vim wget curl telnet bash-completion zip iproute && \
yum clean all && \
rm -f /etc/localtime && \
ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localitime

[root@node1 centos]# docker build -t centos_dayu_tomcat:v1.0 .

2、构建jdk镜像

[root@node1 jpress]# cd /data/dockerfile/app/jdk
[root@node1 jdk]# vim Dockerfile
FROM centos_dayu_tomcat:v1.0
LABEL maintainer="www.wang.org" ver="centos_jdk:v1.0"
ENV version=1.8.0_341

ADD jdk-8u341-linux-x64.tar.gz /usr/local/

RUN cd /usr/local/ && \
ln -s jdk${version}/ jdk && \
echo -e "export JAVA_HOME=/usr/local/jdk \nexport PATH=$PATH:/usr/local/jdk/bin" > /etc/profile.d/jdk.sh #有的系统镜像需要加e有的不需要,看基础bash类型,如果是sh不需要加,如果是bash需要加

ENV JAVA_HOME /usr/local/jdk
ENV PATH $PATH:${JAVA_HOME}/bin

[root@node1 jdk]# docker build -t centos_jdk:v1.0 .

[root@node1 jdk]# docker run -it --rm centos_jdk:v1.0 bash
[root@5246a87f7c1e /]# java
java javac javafxpackager javap javaws
java-rmi.cgi javadoc javah javapackager
[root@5246a87f7c1e /]# java -version
java version "1.8.0_341"
Java(TM) SE Runtime Environment (build 1.8.0_341-b10)
Java HotSpot(TM) 64-Bit Server VM (build 25.341-b10, mixed mode)
[root@5246a87f7c1e /]# exit

3、构建tomcat镜像

[root@node1 jdk]# cd /data/dockerfile/app/tomcat/

[root@node1 tomcat]# vim Dockerfile

FROM centos_jdk:v1.0
LABEL maintainer="www.wang.org" version="centos_tomcat:v1.0"
ENV version apache-tomcat-9.0.65

ADD ${version}.tar.gz /usr/local/

RUN cd /usr/local/ && \
ln -s ${version} tomcat

[root@node1 tomcat]# vim build.sh
docker build -t centos_tomcat:v1.0 .

[root@node1 tomcat]# bash build.sh

4、构建业务镜像1

[root@node1 tomcat]# mkdir tomcat-app{1,2}
[root@node1 tomcat]# cd tomcat-app1
[root@node1 tomcat-app1]# vim Dockerfile

FROM ubuntu_tomcat:v1.0

LABEL maintainer="www.wang.org"

ADD server.xml /usr/local/tomcat/conf/server.xml

ADD run_tomcat.sh /usr/local/tomcat/bin/

ADD app.tar.gz /data/tomcat/webapps/


EXPOSE 8080

CMD ["/usr/local/tomcat/bin/run_tomcat.sh"]

[root@node1 tomcat-app1]# cat app/index.jsp
Tomcat Page in app1
[root@node1 tomcat-app1]# cat server.xml
......
<Host name="localhost" appBase="/data/tomcat/webapps"
unpackWARs="true" autoDeploy="true">
......

[root@node1 tomcat-app1]# vim run_tomcat.sh
echo "nameserver 180.76.76.76" > /etc/resolv.conf
/usr/local/tomcat/bin/catalina.sh start
tail -f /etc/hosts

[root@node1 tomcat-app1]# vim build.sh
docker build -t tomcat-web:app1 .
[root@node1 tomcat-app1]# bash build.sh

[root@node1 tomcat-app1]# docker run -d --rm -p 8090:8080 tomcat-web:app1
[root@node1 tomcat-app1]# docker exec -it e253cf58b7f4 bash
[root@e253cf58b7f4 /]# /usr/share/tomcat/bin/catalina.sh start
[root@e253cf58b7f4 /]# exit

[root@node1 tomcat-app1]# curl 127.0.0.1:8090/app/ #测试访问
Tomcat Page in app

4、构建业务镜像2

[root@node1 tomcat]# cd tomcat-app2
[root@node1 tomcat-app2]# cp -r ../tomcat-app1/* .
[root@node1 tomcat-app2]# echo "Tomcat Page in app2" > app/index.html
[root@node1 tomcat-app2]# rm -f app.tar.gz
[root@node1 tomcat-app2]# tar zcf app.tar.gz app
# Dockerfile不变
# run_tomcat.sh 不变
# server.xml 不变
[root@node1 tomcat-app2]# vim build.sh
docker build -t tomcat-web:app2 .

[root@node1 tomcat-app2]# bash build.sh
[root@node1 tomcat-app2]# docker run -d -p 8060:8080 tomcat-web:app2

[root@node1 tomcat-app2]# curl 127.0.0.1:8060/app/ #测试访问
Tomcat Page in app2

4、构建haproxy镜像
4-1、下载haproxy源码

[root@node1 ~]# mkdir -p /data/dockerfile/app/haproxy/
[root@node1 ~]# cd /data/dockerfile/app/haproxy/
[root@node1 haproxy]# wget https://www.haproxy.org/download/2.6/src/haproxy-2.6.6.tar.gz

4-2、准备haproxy启动脚本

[root@node1 haproxy]# vim run_haproxy.sh
/apps/haproxy/sbin/haproxy -f /etc/haproxy/haproxy.cfg
tail -f /etc/hosts
[root@node1 haproxy]# chmod +x run_haproxy.sh

4-3、准备haproxy配置文件

[root@node1 haproxy]# vim haproxy.cfg
global
chroot /apps/haproxy
#stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin
uid 99
gid 99
daemon
pidfile /apps/haproxy/run/haproxy.pid
log 127.0.0.1 local3 info
defaults
option http-keep-alive
option forwardfor
mode http
timeout connect 300000ms
timeout client 300000ms
timeout server 300000ms

listen stats
mode http
bind 0.0.0.0:9999
stats enable
log global
stats uri /haproxy-status
stats auth haadmin:123456

listen web_port
bind 0.0.0.0:80
mode http
log global
balance roundrobin
server web1 192.168.100.202:8080 check inter 3000 fall 2 rise 5
server web2 192.168.100.203:8080 check inter 3000 fall 2 rise 5

4-4、编写Dockerfile文件

[root@node1 haproxy]# vim Dockerfile 

FROM centos_dayu:v1.0
LABEL maintainer="www.wang.org" version="centos_haproxy:v1.0"

ADD haproxy-2.6.6.tar.gz /usr/local/src/

RUN cd /usr/local/src/haproxy-2.6.6 && \
make ARCH=x86_64 TARGET=linux-glibc USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1 USE_SYSTEMD=1 USE_CPU_AFFINITY=1 PREFIX=/apps/haproxy && \
make install PREFIX=/apps/haproxy && \
ln -s /apps/haproxy/sbin/haproxy /usr/sbin/ && \
mkdir /apps/haproxy/run && \
rm -rf /usr/local/src/haproxy*

ADD haproxy.cfg /etc/haproxy/
ADD run_haproxy.sh /usr/bin/

EXPOSE 80 9999

CMD ["/usr/bin/run_haproxy.sh"]

4-5、生成镜像

[root@node1 haproxy]# vim build.sh
docker build -t centos_haproxy:v1.0 .

[root@node1 haproxy]# bash build.sh

4-6、启动容器

[root@node1 haproxy]# docker run -d -p 80:80 -p 9999:9999 centos_haproxy:v1.0
eb5174a46db1497fe3fdc23fae53d3d06e7ab0cdbb015cc253db7c9121b6691a

4-7、另外两台主机启动容器

#导出镜像
[root@node1 haproxy]# docker save tomcat-web:app1 > /data/tomcat-web.tar.gz
[root@node1 haproxy]# docker save tomcat-web:app2 > /data/tomcat_web2.tar.gz

#将镜像复制到另外两台主机
[root@node1 haproxy]# scp /data/tomcat-web.tar.gz 192.168.100.202:/data/
[root@node1 haproxy]# scp /data/tomcat_web2.tar.gz 192.168.100.203:/data/

#在另外两台主机上执行下面操作导入镜像
[root@DY-Ubuntu-02 ~]#docker load -i /data/tomcat-web.tar.gz

[root@DY-Ubuntu-03 ~]#docker load -i /data/tomcat_web2.tar.gz

#在另外两台主机上创建相关容器
[root@DY-Ubuntu-02 ~]#docker run -d -p 8080:8080 tomcat-web:app1

[root@DY-Ubuntu-03 ~]#docker run -d -p 8080:8080 tomcat-web:app2

4-8、访问验证

[root@DY-Ubuntu-01 ~]#curl 192.168.100.102/app/
Tomcat Page in app2
[root@DY-Ubuntu-01 ~]#curl 192.168.100.102/app/
Tomcat Page in app1
[root@DY-Ubuntu-01 ~]#curl 192.168.100.102/app/
Tomcat Page in app2
[root@DY-Ubuntu-01 ~]#curl 192.168.100.102/app/
Tomcat Page in app1

Docker从入门到精通_ubuntu_03

Docker从入门到精通_nginx_04

Docker从入门到精通_docker_05

Docker从入门到精通_ubuntu_06

5、基于 Alpine 基础镜像制作 Nginx 镜像

##下载alpine镜像,打新标签
[root@node1 ~]# docker pull alpine
[root@node1 ~]# docker tag alpine alpine_dayu:v1.0
[root@node1 ~]# mkdir /data/dockerfile/system/alpine
[root@node1 ~]# cd /data/dockerfile/system/alpine
#准备apk源文件
[root@node1 alpine]# vim repositories
http://mirrors.aliyun.com/alpine/v3.16/main
http://mirrors.aliyun.com/alpine/v3.16/community

##编写Dockerfile文件
[root@node1 alpine]# vim Dockerfile
FROM alpine_dayu:v1.0
LABEL maintainer="www.wang.org" version="alpine_dayu:v1.1"
COPY repositories /etc/apk/repositories
RUN apk update && \
apk --no-cache add iotop gcc libgcc libc-dev libcurl libc-utils pcre-dev zlib-dev libnfs make pcre pcre2 zip unzip net-tools pstree wget libevent libevent-dev iproute2

#制作镜像脚本
[root@node1 alpine]# vim build.sh
docker build -t alpine_dayu:v1.1 .

#生成镜像
[root@node1 alpine]# bash build.sh

[root@node1 alpine]# mkdir /data/dockerfile/app/nginx/alpine_nginx
[root@node1 alpine]# cd /data/dockerfile/app/nginx/alpine_nginx

[root@node1 alpine_nginx]# wget http://nginx.org/download/nginx-1.22.0.tar.gz

[root@node1 alpine_nginx]# echo Test Page based nginx-alpine > index.html

[root@node1 alpine_nginx]# cp ../nginx-1.22.0/conf/nginx.conf .
[root@node1 alpine_nginx]# vim nginx.conf
......
# user nginx;
worker_processes auto;
......
location / {
root /data/nginx/html;

[root@node1 alpine_nginx]# vim Dockerfile
FROM alpine_dayu:v1.1
LABEL maintainer="www.wang.org"

ADD nginx-1.22.0.tar.gz /usr/local/src/

RUN cd /usr/local/src/nginx-1.22.0 && \
./configure --prefix=/apps/nginx && \
make && make install && \
ln -s /apps/nginx/sbin/nginx /usr/bin/
COPY nginx.conf /apps/nginx/conf/nginx.conf

ADD index.html /data/nginx/html/index.html

EXPOSE 80 443

CMD ["nginx"]

[root@node1 alpine_nginx]# vim build.sh
docker build -t alpine_nginx:v1.0 .
[root@node1 alpine_nginx]# bash build.sh
[root@node1 alpine_nginx]# docker run -it alpine_nginx:v1.0 sh
/ # nginx
/ # ss -ntlp
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 128 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=8,fd=6))
/ # exit

6、基于 Ubuntu 基础镜像制作 Nginx 镜像

[root@node1 ~]# docker pull ubuntu:20.04
[root@node1 ~]# mkdir /data/dockerfile/system/ubuntu/ubuntu_dayu:v1.0
[root@node1 ~]# cd /data/dockerfile/system/ubuntu/ubuntu_dayu:v1.0

[root@node1 ubuntu_dayu:v1.0]#vim sources.list
[root@node1 ubuntu_dayu:v1.0]#cp ../../../app/nginx/alpine_nginx/nginx-1.22.0.tar.gz .
[root@node1 ubuntu_dayu:v1.0]#cp ../../../app/nginx/alpine_nginx/nginx.conf .
[root@node1 ubuntu_dayu:v1.0]#cp ../../../app/nginx/alpine_nginx/index.html .
[root@node1 ubuntu_dayu:v1.0]#vim Dockerfile

FROM ubuntu_dayu:v1
LABEL maintainer="www.wang.org" version="ubuntu_dayu:v1.0"

COPY sources.list /etc/apt/sources.list

RUN apt update && \
apt install -y nfs-kernel-server nfs-common gcc openssh-server lrzsz tree openssl libssl-dev libpcre3 libpcre3-dev zlib1g-dev unzip zip make

ADD nginx-1.22.0.tar.gz /usr/local/src/

RUN cd /usr/local/src/nginx-1.22.0 && \
./configure --prefix=/apps/nginx && \
make && make install && \
ln -s /apps/nginx/sbin/nginx /usr/bin && \
rm -rf /usr/local/src/nginx-1.22.0/*

ADD nginx.conf /apps/nginx/conf/nginx.conf
ADD index.html /data/nginx/html/index.html

RUN groupadd -g 2000 nginx && \
useradd -u 2000 -g nginx -s /sbin/nologin nginx && \
chown -R nginx.nginx /apps/nginx/ /data/nginx

EXPOSE 80 443

CMD ["nginx"]
[root@node1 ubuntu_dayu:v1.0]#vim build.sh

[root@node1 ~]# docker run -it -p 9090:80 ubuntu_nginx:v1.0 bash
root@d398aae95e41:/# nginx
[root@node1 ~]# curl 127.0.0.1:9090
Test Page based nginx-alpine

五、Docker 数据管理

Docker镜像由多个只读层叠加而成,启动容器时,Docker会加载只读镜像层并在镜像栈顶部添加一个读写层 如果运行中的容器修改了现有的一个已经存在的文件,那该文件将会从读写层下面的只读层复制到读写层,该文件的只读版本仍然存在,只是已经被读写层中该文件的副本所隐藏,此即“写时复制(COW copyon write)"机制 如果将正在运行中的容器修改生成了新的数据,那么新产生的数据将会被复制到读写层,进行持久化保存,这个读写层也就是容器的工作目录,也为写时复制(COW) 机制。 COW机制节约空间,但会导致性低下,虽然关闭重启容器,数据不受影响,但会随着容器的删除,其对应的可写层也会随之而删除,即数据也会丢失.如果容器需要持久保存数据,并不影响性能可以用数据卷技术实现

5-1、Docker容器的分层

容器的数据分层目录 LowerDir: image 镜像层,即镜像本身,只读 UpperDir: 容器的上层,可读写 ,容器变化的数据存放在此处 MergedDir: 容器的文件系统,使用Union FS(联合文件系统)将lowerdir 和 upperdir 合并完成后给容器使用,最终呈现给用户的统一视图 WorkDir: 容器在宿主机的工作目录,挂载后内容会被清空,且在使用过程中其内容用户不可见

5-2、容器数据持久保存方式

数据卷(Data Volume): 直接将宿主机目录挂载至容器的指定的目录 ,推荐使用此种方式,此方式较常用 数据卷容器(Data Volume Container): 间接使用宿主机空间,数据卷容器是将宿主机的目录挂载至一个专门的数据卷容器,然后让其他容器通过数据卷容器读写宿主机的数据 ,此方式不常用

5-2-1、数据卷

数据卷使用场景

  • 数据库
  • 日志输出
  • 静态web页面
  • 应用配置文件
  • 多容器间目录或文件共享

数据卷的特点

  • 数据卷是目录或者文件,并且可以在多个容器之间共同使用,实现容器之间共享和重用
  • 对数据卷更改数据在所有容器里面会立即更新。
  • 数据卷的数据可以持久保存,即使删除,使用该容器卷的容器也不影响。
  • 在容器里面的写入数据不会影响到镜像本身,即数据卷的变化不会影响镜像的更新
  • 依赖于宿主机目录,宿主机出问题,上面容器会受影响,当宿主机较多时,不方便统一管理
  • 匿名和命名数据卷在容器启动时初始化,如果容器使用的镜像在挂载点包含了数据,会拷贝到新初始化的数据卷中

数据卷分类

启动容器时,可以指定使用数据卷实现容器数据的持久化,数据卷有三种

  • 指定宿主机目录或文件: 指定宿主机的具体路径和容器路径的挂载关系,此方式不会创建数据卷
  • 匿名卷: 不指定数据名称,只指定容器内目录路径充当挂载点,docker自动指定宿主机的路径进行挂载,此方式会创建匿名数据卷,Dockerfile中VOLUME指定的卷即为此种
  • 命名卷: 指定数据卷的名称和容器路径的挂载关系,此方式会创建命名数据卷

#指定宿主机目录或文件格式:
-v <宿主机绝对路径的目录或文件>:<容器目录或文件>[:ro] #将宿主机目录挂载容器目录,两个目录都可自动创建

#匿名卷,只指定容器内路径,没有指定宿主机路径信息,宿主机自动生成/var/lib/docker/volumes/<卷ID>/_data目录,并挂载至容器指定路径
-v <容器内路径>
#示例:
docker run --name nginx -v /etc/nginx nginx

#命名卷将固定的存放在/var/lib/docker/volumes/<卷名>/_data
-v <卷名>:<容器目录路径>
#可以通过以下命令事先创建,如可没有事先创建卷名,docker run时也会自动创建卷
docker volume create <卷名>
#示例:
docker volume create vol1 #也可以事先不创建
docker run -d -p 80:80 --name nginx01 -v vol1:/usr/share/nginx/html nginx

#docker rm 的 -v 选项可以删除容器时,同时删除相关联的匿名卷
-v, --volumes Remove the volumes associated with the container

管理数据卷命令

docker volume COMMAND
Commands:
create Create a volume
inspect Display detailed information on one or more volumes
ls List volumes
prune Remove all unused local volumes
rm Remove one or more volumes

查看数据卷的挂载关系

docker inspect --format="{{.Mounts}}" <容器ID>

[root@node1 ~]# docker volume create mysql-vol
[root@node1 ~]# docker volume rm mysql-vol
mysql-vol
[root@node1 ~]# docker volume ls
DRIVER VOLUME NAME
local 8fbea101f6acea1a84587d57aa4ebcb9002f0b65ef4dd8b150eb150eba105808

5-3、MySQL使用的数据卷

[root@DY-Ubuntu-03 ~]#docker pull mysql
[root@DY-Ubuntu-03 ~]#docker run -d --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -v /data/mysql:/var/lib/mysql/ mysql
[root@DY-Ubuntu-03 ~]#mysql -uroot -p123456 -h127.1
mysql> create database test;

#删除容器,数据存放在挂载数据卷中,不会删除
[root@DY-Ubuntu-03 ~]#docker rm -fv mysql
[root@DY-Ubuntu-03 ~]#ls /data/mysql/
'#ib_16384_0.dblwr' binlog.index ib_logfile0 performance_schema test
'#ib_16384_1.dblwr' ca-key.pem ib_logfile1 private_key.pem undo_001
'#innodb_temp' ca.pem ibdata1 public_key.pem undo_002
auto.cnf client-cert.pem ibtmp1 server-cert.pem
binlog.000001 client-key.pem mysql server-key.pem
binlog.000002 ib_buffer_pool mysql.ibd sys

#重新创建新容器,之前数据还在
[root@DY-Ubuntu-03 ~]#docker run -d --name mysql1 -p 3306:3306 -v /data/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql

[root@DY-Ubuntu-03 ~]#mysql -uroot -p123456 -h127.1
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| test |
+--------------------+
5 rows in set (0.01 sec)

5-4、实现 wordpress 持久化

[root@DY-Ubuntu-03 ~]#docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_DATABASE=wordpress -e MYSQL_USER=wordpress -e MYSQL_PASSWORD=123456 --name mysql -v /data/mysql:/var/lib/mysql --restart=always mysql:8.0.30-oracle

[root@DY-Ubuntu-03 ~]#docker run -d -p 80:80 --name wordpress -v /data/wordpress:/var/www/html --restart=always wordpress:php7.4-apache

Docker从入门到精通_nginx_07

六、Docker 网络管理

每次新建容器后

  • 宿主机多了一个虚拟网卡,和容器的网卡组合成一个网卡,比如: 137: veth8ca6d43@if136,而在容器内的网卡名为136,可以看出和宿主机的网卡之间的关联
  • 容器会自动获取一个172.17.0.0/16网段的随机地址,默认从172.17.0.2开始分配给第1个容器使用,第2个容器为172.17.0.3,以此类推
  • 容器获取的地址并不固定,每次容器重启,可能会发生地址变化

默认情况下

  • 同一个宿主机的不同容器之间可以相互通信

dockerd --icc Enable inter-container communication (default true)
--icc=false #此配置可以禁止同一个宿主机的容器之间通信

  • 不同宿主机之间的容器IP地址重复,默认不能相互通信

#禁止同一宿主机容器间访问
#dockerd 的 --icc=false 选项可以禁止同一个宿主机的不同容器间通信

[root@DY-Ubuntu-03 ~]#vim /usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H unix://var/run/docker.sock --icc=false
[root@DY-Ubuntu-03 ~]#systemctl daemon-reload
[root@DY-Ubuntu-03 ~]#systemctl restart docker.service

# [root@DY-Ubuntu-03 ~]#docker run -it --rm alpine:v3.15 #测试无法ping同另一容器
/ # ping 172.17.0.5
PING 172.17.0.5 (172.17.0.5): 56 data bytes

6-1、修改默认docker0网桥的网络配置

默认docker后会自动生成一个docker0的网桥,使用的IP是172.17.0.1/16,可能和宿主机的网段发生冲突,可以将其修改为其它网段的地址,避免冲突

# 方法1:
[root@node1 ~]# vim /usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --bip=192.168.188.1/24
[root@node1 ~]# systemctl daemon-reload
[root@node1 ~]# systemctl restart docker


# 方法2:
[root@DY-Ubuntu-03 ~]#vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://pgavrk5n.mirror.aliyuncs.com"],
"bip": "172.77.7.1/24"
}

[root@DY-Ubuntu-03 ~]#systemctl restart docker

#注意两种方法不可混用,否则将无法启动docker服务

6-2、修改默认网络设置使用自定义网桥

新建容器默认使用docker0的网络配置,可以修改默认指向自定义的网桥网络

#用自定义的网桥代替默认的docker0
[root@DY-Ubuntu-03 ~]#apt install -y bridge-utils
[root@DY-Ubuntu-03 ~]#brctl addbr br0
[root@DY-Ubuntu-03 ~]#brctl show

[root@DY-Ubuntu-03 ~]#ip a a 172.66.66.1/24 dev br0
[root@DY-Ubuntu-03 ~]#ip a
br0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 52:00:13:60:53:f8 brd ff:ff:ff:ff:ff:ff
inet 172.66.66.1/24 scope global br0

[root@DY-Ubuntu-03 ~]#dockerd --help # 查看dockerd支持的命令
[root@DY-Ubuntu-03 ~]#vim /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H unix://var/run/docker.sock -b=br0

[root@DY-Ubuntu-03 ~]#systemctl daemon-reload
[root@DY-Ubuntu-03 ~]#systemctl restart docker.service

[root@DY-Ubuntu-03 ~]#docker exec 030606ffcfe5 hostname -i
172.66.66.3

6-3、容器名称互联

新建容器时,docker会自动分配容器名称,容器ID和IP地址,导致容器名称,容器ID和IP都不固定,那么如何区分不同的容器,实现和确定目标容器的通信呢?解决方案是给容器起个固定的名称,容器之间通过固定名称实现确定目标的通信 有两种固定名称:

  • 容器名称
  • 容器名称的别名

注意: 两种方式都最少需要两个容器才能实现

6-3-1、容器名称介绍

即在同一个宿主机上的容器之间可以通过自定义的容器名称相互访问,比如: 一个业务前端静态页面是使用nginx,动态页面使用的是tomcat,另外还需要负载均衡调度器,如: haproxy 对请求调度至nginx和tomcat的容器,由于容器在启动的时候其内部IP地址是DHCP 随机分配的,而给容器起个固定的名称,则是相对比较固定的,因此比较适用于此场景

注意: 如果被引用的容器地址变化,必须重启当前容器才能生效

6-3-2、容器名称实现

docker run 创建容器,可使用--link选项实现容器名称的引用,其本质就是在容器内的/etc/hosts中添加--link后指定的容器的IP和主机名的对应关系,从而实现名称解析

--link list #Add link to another container
格式:
docker run --name <容器名称> #先创建指定名称的容器
docker run --link <目标通信的容器ID或容器名称> #再创建容器时引用上面容器的名称

6-3-3、使用容器名称进行容器间通信

#创建第一个指定容器名称的容器
[root@DY-Ubuntu-03 ~]#docker run -it -d --name server1 --rm alpine:v3.15
[root@DY-Ubuntu-03 ~]#docker exec server1 cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.66.66.4 c588e8235098

# 新建第二个容器时引用第一个容器的名称
[root@DY-Ubuntu-03 ~]#docker run -it -d --rm --name server2 --link server1 alpine:v3.15
[root@DY-Ubuntu-03 ~]#docker exec server2 cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.66.66.4 server1 c588e8235098
172.66.66.5 8459fe7a44d2

[root@DY-Ubuntu-03 ~]#docker exec server2 ping server1
PING server1 (172.66.66.4): 56 data bytes
64 bytes from 172.66.66.4: seq=0 ttl=64 time=2.458 ms
64 bytes from 172.66.66.4: seq=1 ttl=64 time=0.305 ms

[root@DY-Ubuntu-03 ~]#docker exec server2 ping c588e8235098
PING c588e8235098 (172.66.66.4): 56 data bytes
64 bytes from 172.66.66.4: seq=0 ttl=64 time=0.567 ms
64 bytes from 172.66.66.4: seq=1 ttl=64 time=0.323 ms

6-3-4、实现 wordpress 和 MySQL 两个容器互连

[root@DY-Ubuntu-03 ~]#mkdir /data/lamp
[root@DY-Ubuntu-03 ~]#vim /data/lamp/env_mysql.list
MYSQL_ROOT_PASSWORD=123456
MYSQL_DATABASE=wordpress
MYSQL_USER=wordpress
MYSQL_PASSWORD=123456

[root@DY-Ubuntu-03 ~]#vim /data/lamp/env_wordpress.list
WORDPRESS_DB_HOST=mysql:3306
WORDPRESS_DB_NAME=wordpress
WORDPRESS_DB_USER=wordpress
WORDPRESS_DB_PASSWORD=123456
WORDPRESS_TABLE_PREFIX=wp_

[root@DY-Ubuntu-03 ~]#mkdir /data/lamp/mysql/ -p
[root@DY-Ubuntu-03 ~]#vim /data/lamp/mysql/mysql_test.cnf
[mysqld]
server-id=100
log-bin=mysql-bin
default_authentication_plugin=mysql_native_password

[root@DY-Ubuntu-03 ~]#docker run -d --name mysql -v /data/lamp/mysql/:/etc/mysql/conf.d -v /data/lampmysql:/var/lib/mysql --env-file=/data/lamp/env_mysql.list -p 3306:3306 mysql:8.0.30-oracle

[root@DY-Ubuntu-03 ~]#docker run -d --name wordpress --link mysql -v /data/wordpress:/var/www.html/wp-content --env-file=/data/lamp/env_wordpress.list -p 80:80 wordpress:php7.4-apache

Docker从入门到精通_nginx_08

Docker从入门到精通_nginx_09

6-4、通过自定义容器别名互联
6-4-1、 容器别名介绍

自定义的容器名称可能后期会发生变化,那么一旦名称发生变化,容器内程序之间也必须要随之发生变化,比如:程序通过固定的容器名称进行服务调用,但是容器名称发生变化之后再使用之前的名称肯定是无法成功调用,每次都进行更改的话又比较麻烦,因此可以使用自定义别名的方式解决,即容器名称可以随意更改,只要不更改别名即可

6-4-2、容器别名实现

docker run --name <容器名称>
#先创建指定名称的容器
docker run --name <容器名称> --link <目标容器名称>:"<容器别名1> <容器别名2> ..."
#给上面创建的容器起别名,来创建新容器

6-4-3、使用容器别名

[root@DY-Ubuntu-03 ~]#docker run -it -d --rm --name server1 alpine:v3.15

[root@DY-Ubuntu-03 ~]#docker run -it -d --rm --name server2 alpine:v3.15

[root@DY-Ubuntu-03 ~]#docker run -it -d --rm --name server3 --link server1:S1 alpine:v3.15

[root@DY-Ubuntu-03 ~]#docker run -it -d --rm --name server4 --link server1:"S1 S2 S3" alpine:v3.15
[root@DY-Ubuntu-03 ~]#docker exec server4 cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.66.66.2 S1 S2 S3 6f6ca2dfa5ef server1
172.66.66.5 2eb6a0945692

[root@DY-Ubuntu-03 ~]#docker exec server4 ping server1
PING server1 (172.66.66.2): 56 data bytes
64 bytes from 172.66.66.2: seq=0 ttl=64 time=0.623 ms
^C
[root@DY-Ubuntu-03 ~]#docker exec server4 ping S1
PING S1 (172.66.66.2): 56 data bytes
64 bytes from 172.66.66.2: seq=0 ttl=64 time=0.466 ms
^C
[root@DY-Ubuntu-03 ~]#docker exec server4 ping S2
PING S2 (172.66.66.2): 56 data bytes
64 bytes from 172.66.66.2: seq=0 ttl=64 time=2.321 ms
^C
[root@DY-Ubuntu-03 ~]#docker exec server4 ping S3
PING S3 (172.66.66.2): 56 data bytes
64 bytes from 172.66.66.2: seq=0 ttl=64 time=0.486 ms
^C

6-5、Docker 网络连接模式
6-5-1、Docker 的网络支持5种网络模式:
  • none
  • bridge
  • host
  • container
  • network-name

查看默认的网络模式有三个

[root@DY-Ubuntu-03 ~]#docker network ls
NETWORK ID NAME DRIVER SCOPE
ee07ac3cc362 bridge bridge local
6e56b0d113cf host host local
57aa7904e72c none null local

6-5-2、网络模式指定

默认新建的容器使用Bridge模式,创建容器时,docker run 命令使用以下选项指定网络模式

docker run --network <mode>
docker run --net=<mode>

<mode>: 可是以下值
none
bridge
host
container:<容器名或容器ID>
<自定义网络名称>

6-5-3、bridge网络模式

可以和外部网络之间进行通信,通过SNAT访问外网,使用DNAT可以让容器被外部主机访问,所以此模式也称为NAT模式

此模式宿主机需要启动ip_forward功能

bridge网络模式特点

  • 网络资源隔离: 不同宿主机的容器无法直接通信,各自使用独立网络
  • 无需手动配置: 容器默认自动获取172.17.0.0/16的IP地址,此地址可以修改
  • 可访问外网: 利用宿主机的物理网卡,SNAT连接外网
  • 外部主机无法直接访问容器: 可以通过配置DNAT接受外网的访问
  • 低性能较低: 因为可通过NAT,网络转换带来更的损耗
  • 端口管理繁琐: 每个容器必须手动指定唯一的端口,容器产生端口冲容

查看bridge模式信息

[root@DY-Ubuntu-03 ~]#docker network inspect bridge

6-5-4、修改默认的 bridge 模式网络配置

有两种方法修改默认的bridge 模式的网络配置,但两种方式只能选一种,否则会导致冲容,docker服务无法启动

修改bridge模式默认的网段方法1

[root@DY-Ubuntu-03 ~]#vim /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H unix://var/run/docker.sock --bip=10.10.10.1/24
[root@DY-Ubuntu-03 ~]#systemctl daemon-reload
[root@DY-Ubuntu-03 ~]#systemctl restart docker.service

修改bridge网络配置方法2

[root@DY-Ubuntu-03 ~]#vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://pgavrk5n.mirror.aliyuncs.com"],
"bip": "10.20.20.1/24"
}
[root@DY-Ubuntu-03 ~]#systemctl restart docker.service

6-5-5、Host 模式

如果指定host模式启动的容器,那么新创建的容器不会创建自己的虚拟网卡,而是直接使用宿主机的网卡和IP地址,因此在容器里面查看到的IP信息就是宿主机的信息,访问容器的时候直接使用宿主机IP+容器端口即可,不过容器内除网络以外的其它资源,如: 文件系统、系统进程等仍然和宿主机保持隔离此模式由于直接使用宿主机的网络无需转换,网络性能最高,但是各容器内使用的端口不能相同,适用于运行容器端口比较固定的业务

Host 网络模式特点:

  • 使用参数 --network host 指定
  • 共享宿主机网络
  • 网络性能无损耗
  • 网络故障排除相对简单
  • 各容器网络无隔离
  • 网络资源无法分别统计
  • 端口管理困难: 容易产生端口冲突
  • 不支持端口映射
6-5-6、none 模式

在使用none 模式后,Docker 容器不会进行任何网络配置,没有网卡、没有IP也没有路由,因此默认无法与外界通信,需要手动添加网卡配置IP等,所以极少使用

none模式特点

  • 使用参数 --network none 指定
  • 默认无网络功能,无法和外部通信
  • 无法实现端口映射
  • 适用于测试环境
6-5-7、Container 模式

使用此模式创建的容器需指定和一个已经存在的容器共享一个网络,而不是和宿主机共享网络,新创建的容器不会创建自己的网卡也不会配置自己的IP,而是和一个被指定的已经存在的容器共享IP和端口范围,因此这个容器的端口不能和被指定容器的端口冲突,除了网络之外的文件系统、进程信息等仍然保持相互隔离,两个容器的进程可以通过lo网卡进行通信

Container 模式特点

  • 使用参数 –-network container:名称或ID 指定
  • 与宿主机网络空间隔离
  • 空器间共享网络空间
  • 适合频繁的容器间的网络通信
  • 直接使用对方的网络,较少使用
6-5-8、通过容器模式实现 wordpress

[root@DY-Ubuntu-03 ~]#docker run -d -p 80:80 --name wordpress -v /data/wordpress:/var/www/html --restart=always wordpress:php7.4-apache

[root@DY-Ubuntu-03 ~]#docker run -d --name mysql --network container:wordpress -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_DATABASE=wordpress -e MYSQL_USER=wordpress -e MYSQL_PASSWORD=123456 -v /data/mysql:/var/lib/mysql mysql:8.0.30-oracle

#注:mysql:8.0.30无法创建wordpress用户,可以使用root用户连接数据库,或者使用8.0.29版本

6-5-9、通过容器模式实现LNP架构

#准备nginx连接php-fpm的配置文件
[root@DY-Ubuntu-03 ~]#vim /data/nginx/conf.d/php.conf
server {
listen 80;
server_name www.wang.org;
root /usr/share/nginx/html;
index index.php;
location ~ \.php$ {
root /usr/share/nginx/html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}

#准备php的测试页文件
[root@DY-Ubuntu-03 ~]#vim /data/nginx/html/index.php
<?php
phpinfo();
?>

#启动nginx
[root@DY-Ubuntu-03 ~]#docker run -d --name nginx -v /data/nginx/conf.d:/etc/nginx/conf.d -v /data/nginx/html:/usr/share/nginx/html -p 80:80 nginx

#启动php-fpm
[root@DY-Ubuntu-03 ~]#docker run -d --network container:nginx --name php-fqm -v /data/nginx/html:/usr/share/nginx/html php:8.1-fpm
#注意:php:8.1-fpm镜像缺少连接数据库的相关包,无法直接连接MySQ

6-5-10、自定义网络模式

除了以上的网络模式,也可以自定义网络,使用自定义的网段地址,网关等信息 注意: 自定义网络内的容器可以直接通过容器名进行相互的访问,而无需使用 --link 可以使用自定义网络模式,实现不同集群应用的独立网络管理,而互不影响,而且在网一个网络内,可以直接利用容器名相互访问,非常便利

#创建自定义网络:
docker network create -d <mode> --subnet <CIDR> --gateway <网关> <自定义网络名称>
#注意mode不支持host和none,默认是bridge模式

#查看自定义网络信息
docker network inspect <自定义网络名称或网络ID>

#引用自定义网络
docker run --network <自定义网络名称> <镜像名称>
docker run --net <自定义网络名称> --ip <指定静态IP> <镜像名称>
#注意:静态IP只支持自定义网络模型

#删除自定义网络
docker network rm <自定义网络名称或网络ID>

注:内置的三个网络(bridge、none、host)无法删除

自定义网络实现

#创建自定义网络
[root@DY-Ubuntu-03 ~]#docker network create --subnet 172.22.22.0/24 --gateway 172.22.22.1 test-net

[root@DY-Ubuntu-03 ~]#docker network ls
NETWORK ID NAME DRIVER SCOPE
7ea982406f22 bridge bridge local
6e56b0d113cf host host local
57aa7904e72c none null local
025b1481f040 test-net bridge local

[root@DY-Ubuntu-03 ~]#docker inspect test-net

#利用自定义的网络创建容器
[root@DY-Ubuntu-03 ~]#docker run -it --rm --network test-net alpine:v3.15 sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
92: eth0@if93: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:16:16:02 brd ff:ff:ff:ff:ff:ff
inet 172.22.22.2/24 brd 172.22.22.255 scope global eth0
valid_lft forever preferred_lft forever

6-5-11、自定义网络中的容器之间通信

#创建第一个容器
[root@DY-Ubuntu-03 ~]#docker run -it --rm --network test-net --name test1 alpine:v3.15 sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
96: eth0@if97: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:16:16:02 brd ff:ff:ff:ff:ff:ff
inet 172.22.22.2/24 brd 172.22.22.255 scope global eth0
valid_lft forever preferred_lft forever
/ # cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.22.22.2 2ba98785f202

#创建第二个容器
[root@DY-Ubuntu-03 ~]#docker run -it --rm --network test-net --name test2 alpine:v3.15 sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
98: eth0@if99: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:16:16:03 brd ff:ff:ff:ff:ff:ff
inet 172.22.22.3/24 brd 172.22.22.255 scope global eth0
valid_lft forever preferred_lft forever
#测试ping第一个容器
/ # ping -c1 test1
PING test1 (172.22.22.2): 56 data bytes
64 bytes from 172.22.22.2: seq=0 ttl=64 time=0.357 ms

结论: 自定义网络中的容器之间可以直接利用容器名进行通信

6-5-12、利用自定义网络实现 wordpress

[root@DY-Ubuntu-03 ~]#docker network create -d bridge --subnet 172.88.8.0/24 --gateway 172.88.8.1 bridge2

[root@DY-Ubuntu-03 ~]#docker run -d -p 8888:80 --name wordpress --network bridge2 -v /data/wordpress:/var/www/html --restart=always wordpress:php7.4-apache
3546b1b6a1410f4eeb11b426b0ff7d0c7968994b36d7424a7fda490c64423376

[root@DY-Ubuntu-03 ~]#docker run -d --network container:wordpress --name mysql -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_DATABASE=wordpress -e MYSQL_USER=wordpress -e MYSQL_PASSWORD=123456 -v /data/mysql:/var/lib/mysql --restart=always mysql:8.0.30-oracle

6-5-13、利用自定义网络实现 Redis Cluster

# 通过脚本创建六个redis容器配置
[root@DY-Ubuntu-03 ~]#for port in {1..6};do mkdir -p /data/redis/node-${port}/conf
cat >> /data/redis/node-${port}/conf/redis.conf <<EOF
port 6379
bind 0.0.0.0
masterauth 123456
cluster-enabled yes
cluster-config-file nodes.conf
cluster-announce-ip 172.33.33.1${port}
cluster-node-timeout 5000
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
requirepass 123456
EOF
done

[root@DY-Ubuntu-03 ~]#cat /data/redis/node-1/conf/redis.conf
port 6379
bind 0.0.0.0
masterauth 123456
cluster-enabled yes
cluster-config-file nodes.conf
cluster-announce-ip 172.33.33.11
cluster-node-timeout 5000
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
requirepass 123456

# 通过脚本运行六个redis容器
[root@DY-Ubuntu-03 ~]#for port in {1..6};do
> docker run -p 637${port}:6379 -p 1667${port}:16379 --name redis-${port} \
> -v /data/redis/node-${port}/data:/data \
> -v /data/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf \
> -d --network net-redis --ip 172.33.33.1${port} redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
> done

#连接redis cluster
[root@DY-Ubuntu-03 ~]#docker exec -it redis-1 /bin/sh

/data # redis-cli -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> exit

# 创建集群
/data # redis-cli -a 123456 --cluster create 172.33.33.11:6379 172.33.33.12:6379 172.33.33.1
3:6379 172.33.33.14:6379 172.33.33.15:6379 172.33.33.16:6379 --cluster-replicas 1
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 172.33.33.15:6379 to 172.33.33.11:6379
Adding replica 172.33.33.16:6379 to 172.33.33.12:6379
Adding replica 172.33.33.14:6379 to 172.33.33.13:6379
M: 040ddee6a483616d8dafeb50e5a0ebb75e44b3e6 172.33.33.11:6379
slots:[0-5460] (5461 slots) master
M: e155995116032657a29880b79004beefffffc17e 172.33.33.12:6379
slots:[5461-10922] (5462 slots) master
M: a7ee3734edccb4bbea33a1518f95cf8ca6e18d36 172.33.33.13:6379
slots:[10923-16383] (5461 slots) master
S: 4e4a89edfc967a90157ff2e18c044a6ad199e13c 172.33.33.14:6379
replicates a7ee3734edccb4bbea33a1518f95cf8ca6e18d36
S: 7da41122fb786548b3bc2e9741bae6ee0db75746 172.33.33.15:6379
replicates 040ddee6a483616d8dafeb50e5a0ebb75e44b3e6
S: 8b1f85d083a4ece07d9fa96009b096b24f1bde16 172.33.33.16:6379
replicates e155995116032657a29880b79004beefffffc17e
Can I set the above configuration? (type 'yes' to accept): yes #输入yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
...
>>> Performing Cluster Check (using node 172.33.33.11:6379)
M: 040ddee6a483616d8dafeb50e5a0ebb75e44b3e6 172.33.33.11:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: 4e4a89edfc967a90157ff2e18c044a6ad199e13c 172.33.33.14:6379
slots: (0 slots) slave
replicates a7ee3734edccb4bbea33a1518f95cf8ca6e18d36
S: 7da41122fb786548b3bc2e9741bae6ee0db75746 172.33.33.15:6379
slots: (0 slots) slave
replicates 040ddee6a483616d8dafeb50e5a0ebb75e44b3e6
S: 8b1f85d083a4ece07d9fa96009b096b24f1bde16 172.33.33.16:6379
slots: (0 slots) slave
replicates e155995116032657a29880b79004beefffffc17e
M: a7ee3734edccb4bbea33a1518f95cf8ca6e18d36 172.33.33.13:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
M: e155995116032657a29880b79004beefffffc17e 172.33.33.12:6379
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

#测试访问 redis cluster

#连接redis cluster
/data # redis-cli -a 123456 -c
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:198
cluster_stats_messages_pong_sent:187
cluster_stats_messages_sent:385
cluster_stats_messages_ping_received:182
cluster_stats_messages_pong_received:198
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:385

127.0.0.1:6379> cluster nodes
4e4a89edfc967a90157ff2e18c044a6ad199e13c 172.33.33.14:6379@16379 slave a7ee3734edccb4bbea33a1518f95cf8ca6e18d36 0 1666233805731 4 connected
7da41122fb786548b3bc2e9741bae6ee0db75746 172.33.33.15:6379@16379 slave 040ddee6a483616d8dafeb50e5a0ebb75e44b3e6 0 1666233804626 5 connected
8b1f85d083a4ece07d9fa96009b096b24f1bde16 172.33.33.16:6379@16379 slave e155995116032657a29880b79004beefffffc17e 0 1666233806537 6 connected
a7ee3734edccb4bbea33a1518f95cf8ca6e18d36 172.33.33.13:6379@16379 master - 0 1666233805229 3 connected 10923-16383
e155995116032657a29880b79004beefffffc17e 172.33.33.12:6379@16379 master - 0 1666233806234 2 connected 5461-10922
040ddee6a483616d8dafeb50e5a0ebb75e44b3e6 172.33.33.11:6379@16379 myself,master - 0 1666233806000 1 connected 0-5460
#看到172.33.33.{11,12,13}为master,172.33.33.{14,15,16}为slave
#以下为master/slave关系
#172.33.33.11<--->172.33.33.15
#172.33.33.12<--->172.33.33.16
#172.33.33.13<--->172.33.33.14

#添加key到redis-2上
127.0.0.1:6379> set name wang
-> Redirected to slot [5798] located at 172.33.33.12:6379
OK

#添加key到redis-1上
172.33.33.12:6379> set title cto
-> Redirected to slot [2217] located at 172.33.33.11:6379
OK

172.33.33.11:6379> get name
-> Redirected to slot [5798] located at 172.33.33.12:6379
"wang"
172.33.33.12:6379> get title
-> Redirected to slot [2217] located at 172.33.33.11:6379
"cto"
172.33.33.11:6379>

#测试故障实现 redis cluster 高可用性

#模拟redis-2故障
[root@DY-Ubuntu-03 ~]#docker stop redis-2
redis-2

#再次查看cluster状态,可以看到redis-2出错
[root@DY-Ubuntu-03 ~]#docker exec -it redis-1 /bin/sh
/data # redis-cli -a 123456 --cluster check 127.0.0.1:6379
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
Could not connect to Redis at 172.33.33.12:6379: Host is unreachable
127.0.0.1:6379 (040ddee6...) -> 1 keys | 5461 slots | 1 slaves.
172.33.33.16:6379 (8b1f85d0...) -> 1 keys | 5462 slots | 0 slaves.
172.33.33.13:6379 (a7ee3734...) -> 0 keys | 5461 slots | 1 slaves.
[OK] 2 keys in 3 masters.
0.00 keys per slot on average.
>>> Performing Cluster Check (using node 127.0.0.1:6379)
M: 040ddee6a483616d8dafeb50e5a0ebb75e44b3e6 127.0.0.1:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: 4e4a89edfc967a90157ff2e18c044a6ad199e13c 172.33.33.14:6379
slots: (0 slots) slave
replicates a7ee3734edccb4bbea33a1518f95cf8ca6e18d36
S: 7da41122fb786548b3bc2e9741bae6ee0db75746 172.33.33.15:6379
slots: (0 slots) slave
replicates 040ddee6a483616d8dafeb50e5a0ebb75e44b3e6
M: 8b1f85d083a4ece07d9fa96009b096b24f1bde16 172.33.33.16:6379 #看到 172.18.0.16提升为新的master
slots:[5461-10922] (5462 slots) master
M: a7ee3734edccb4bbea33a1518f95cf8ca6e18d36 172.33.33.13:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.


/data # redis-cli -a 123456 -c
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> cluster nodes
4e4a89edfc967a90157ff2e18c044a6ad199e13c 172.33.33.14:6379@16379 slave a7ee3734edccb4bbea33a1518f95cf8ca6e18d36 0 1666234331915 4 connected
7da41122fb786548b3bc2e9741bae6ee0db75746 172.33.33.15:6379@16379 slave 040ddee6a483616d8dafeb50e5a0ebb75e44b3e6 0 1666234331514 5 connected
8b1f85d083a4ece07d9fa96009b096b24f1bde16 172.33.33.16:6379@16379 master - 0 1666234331513 7 connected 5461-10922
a7ee3734edccb4bbea33a1518f95cf8ca6e18d36 172.33.33.13:6379@16379 master - 0 1666234330909 3 connected 10923-16383
e155995116032657a29880b79004beefffffc17e 172.33.33.12:6379@16379 master,fail - 1666234122624 1666234121819 2 connected
040ddee6a483616d8dafeb50e5a0ebb75e44b3e6 172.33.33.11:6379@16379 myself,master - 0 1666234331000 1 connected 0-5460
127.0.0.1:6379> get name
-> Redirected to slot [5798] located at 172.33.33.16:6379
"wang"
172.33.33.16:6379> get title
-> Redirected to slot [2217] located at 172.33.33.11:6379
"cto"
172.33.33.11:6379>

6-5-14、修改iptables实现同一宿主机上的不同网络的容器间通信

开两个容器,一个使用自定义网络容器,一个使用默认brideg网络的容器,默认因iptables规则导致无法通信

[root@DY-Ubuntu-03 ~]#cat /proc/sys/net/ipv4/ip_forward
1
[root@DY-Ubuntu-03 ~]#iptables-save > rules
[root@DY-Ubuntu-03 ~]#vim rules1
......
-A DOCKER-ISOLATION-STAGE-2 -o br-008c88b87506 -j ACCEPT #需改DROP为ACCEPT
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j ACCEPT #需改DROP为ACCEPT
......
[root@DY-Ubuntu-03 ~]#iptables-restore < rules1

[root@DY-Ubuntu-03 ~]#docker run -it --rm --name test1 alpine:v3.15 sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
133: eth0@if134: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:0a:14:14:02 brd ff:ff:ff:ff:ff:ff
inet 10.20.20.2/24 brd 10.20.20.255 scope global eth0
valid_lft forever preferred_lft forever

#另开一个终端启动另一网桥容器
[root@DY-Ubuntu-03 ~]#docker run -it --rm --name test2 --network test-net alpine:v3.15 sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
131: eth0@if132: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:0a:0a:0a:02 brd ff:ff:ff:ff:ff:ff
inet 10.10.10.2/24 brd 10.10.10.255 scope global eth0
valid_lft forever preferred_lft forever
/ # ping 10.20.20.2
PING 10.20.20.2 (10.20.20.2): 56 data bytes
64 bytes from 10.20.20.2: seq=0 ttl=63 time=0.733 ms
64 bytes from 10.20.20.2: seq=1 ttl=63 time=0.249 ms

6-5-15、通过解决docker network connect 实现同一个宿主机不同网络的容器间通信

可以使用docker network connect命令实现同一个宿主机不同网络的容器间相互通信

#开启两个容器,test1在
[root@DY-Ubuntu-03 ~]#docker run -it -d --name test1 alpine:v3.15 # test1在10.20.20.0网段

[root@DY-Ubuntu-03 ~]#docker run -it -d --name test2 --network test-net alpine:v3.15 # test1在10.10.10.0网段

#让默认网络中容器test1可以连通自定义网络test-net的容器test2
[root@DY-Ubuntu-03 ~]#docker network connect test-net test1

#在test1容器中可以看到新添加了一个网卡,并且分配了test-net网络的IP信息
[root@DY-Ubuntu-03 ~]#docker exec -it test1 sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
135: eth0@if136: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:0a:14:14:02 brd ff:ff:ff:ff:ff:ff
inet 10.20.20.2/24 brd 10.20.20.255 scope global eth0
valid_lft forever preferred_lft forever
139: eth1@if140: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:0a:0a:0a:03 brd ff:ff:ff:ff:ff:ff
inet 10.10.10.3/24 brd 10.10.10.255 scope global eth1
valid_lft forever preferred_lft forever
/ # ping -c1 10.10.10.2 #test1可以连接test2容器
PING 10.10.10.2 (10.10.10.2): 56 data bytes
64 bytes from 10.10.10.2: seq=0 ttl=64 time=2.273 ms

##在test2容器中没有变化,仍然无法连接test1
[root@DY-Ubuntu-03 ~]#docker exec -it test2 sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
137: eth0@if138: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:0a:0a:0a:02 brd ff:ff:ff:ff:ff:ff
inet 10.10.10.2/24 brd 10.10.10.255 scope global eth0
valid_lft forever preferred_lft forever
/ # ping 10.20.20.2
PING 10.20.20.2 (10.20.20.2): 56 data bytes
^C

#让自定义网络中容器test2可以连通默认网络的容器test1
[root@DY-Ubuntu-03 ~]#docker network connect bridge test2
[root@DY-Ubuntu-03 ~]#docker network inspect bridge
[root@DY-Ubuntu-03 ~]#docker exec -it test2 sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
137: eth0@if138: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:0a:0a:0a:02 brd ff:ff:ff:ff:ff:ff
inet 10.10.10.2/24 brd 10.10.10.255 scope global eth0
valid_lft forever preferred_lft forever
141: eth1@if142: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:0a:14:14:03 brd ff:ff:ff:ff:ff:ff
inet 10.20.20.3/24 brd 10.20.20.255 scope global eth1
valid_lft forever preferred_lft forever
/ # ping 10.20.20.2 #test2可以连接test1容器
PING 10.20.20.2 (10.20.20.2): 56 data bytes
64 bytes from 10.20.20.2: seq=0 ttl=64 time=2.391 ms
64 bytes from 10.20.20.2: seq=1 ttl=64 time=0.245 ms

#在test2中可以利test1容器名通信
/ # ping -c1 test2
PING test2 (10.10.10.2): 56 data bytes
64 bytes from 10.10.10.2: seq=0 ttl=64 time=0.443 ms

#在test1中可以利用test2容器名通信
/ # ping -c1 test1
PING test1 (10.10.10.3): 56 data bytes
64 bytes from 10.10.10.3: seq=0 ttl=64 time=0.992 ms

# 断开不同网络中容器的通信

#将test1 断开和网络test-net中其它容器的通信
[root@DY-Ubuntu-03 ~]#docker network disconnect test-net test1
[root@DY-Ubuntu-03 ~]#docker exec -it test1 sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
135: eth0@if136: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:0a:14:14:02 brd ff:ff:ff:ff:ff:ff
inet 10.20.20.2/24 brd 10.20.20.255 scope global eth0
valid_lft forever preferred_lft forever
/ # ping -c1 10.10.10.2 #在容器test1中无法和test2通信
PING 10.10.10.2 (10.10.10.2): 56 data bytes

#将test2 断开和默认网络中其它容器的通信
[root@DY-Ubuntu-03 ~]#docker network disconnect bridge test2
[root@DY-Ubuntu-03 ~]#docker exec -it test2 sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
137: eth0@if138: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:0a:0a:0a:02 brd ff:ff:ff:ff:ff:ff
inet 10.10.10.2/24 brd 10.10.10.255 scope global eth0
valid_lft forever preferred_lft forever
/ # ping -c1 10.20.20.2 #在容器test2中无法和test1通信
PING 10.20.20.2 (10.20.20.2): 56 data bytes

6-5-16、利用桥接实现跨宿主机的容器间互联

同一个宿主机之间的各个容器之间是可以直接通信的,但是如果访问到另外一台宿主机的容器呢?

Docker从入门到精通_ubuntu_10

#分别将两个宿主机都执行下面操作,并且两个宿主机的docker0都是同网段
#apt -y install bridge-utils
#brctl addif docker0 eth0
#执行完以上操作,xshell就断了,只能在虚拟终端测试

#第一个宿主机:
#docker run -it -d --name b3 busybox #启动第一个容器,占用IP地址2
#docker run -it -d --name b4 busybox #启动第二个容器,默认分配的ip为3
#docker rm -f b1 #删除第一个容器,这时宿主机只有一个ip为3的容器


#第二个宿主机:
#docker run -it --name b1 busybox #启动第一个容器,默认分配的ip为2
#测试访问:
ip a
ping 10.20.20.3 #可以看到能ping通
=====================
#测试访问:
# 第一个宿主机测试:
docker exec -it b4 sh
ip a
ping 10.20.20.2 #可以看到能ping通

6-5-17、利用NAT实现跨主机的容器间互联

docker跨主机互联实现说明

跨主机互联是说A宿主机的容器可以访问B主机上的容器,但是前提是保证各宿主机之间的网络是可以相互通信的,然后各容器才可以通过宿主机访问到对方的容器

实现原理: 是在宿主机做一个网络路由就可以实现A宿主机的容器访问B主机的容器的目的

注意: 此方式只适合小型网络环境,复杂的网络或者大型的网络可以使用google开源的k8s进行互联

#修改各宿主机网段
Docker默认网段是172.17.0.x/24,而且每个宿主机都是一样的,因此要做路由的前提就是各个主机的网络不能一致

# 第一个宿主机A上更改网段为10.10.10.1/24
[root@node1 ~]# vim /usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --bip=10.10.10.1/24
[root@node1 ~]# systemctl daemon-reload
[root@node1 ~]# systemctl restart docker.service

#第二个宿主机同样方法更改网段为10.20.20.1/24,步骤同上

#在两个宿主机分别启动一个容器

#第一个宿主机启动容器server1
[root@node1 ~]# docker run -it --name server1 --rm alpine sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
12: eth0@if13: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:0a:0a:0a:02 brd ff:ff:ff:ff:ff:ff
inet 10.10.10.2/24 brd 10.10.10.255 scope global eth0
valid_lft forever preferred_lft forever
/ # route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 10.10.10.1 0.0.0.0 UG 0 0 0 eth0
10.10.10.0 0.0.0.0 255.255.255.0 U 0 0 0 eth

======================================================================
#第二个宿主机启动容器server2
[root@DY-Ubuntu-03 ~]#docker run -it --rm --name server2 alpine sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
9: eth0@if10: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:0a:14:14:02 brd ff:ff:ff:ff:ff:ff
inet 10.20.20.2/24 brd 10.20.20.255 scope global eth0
valid_lft forever preferred_lft forever
/ # route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 10.20.20.1 0.0.0.0 UG 0 0 0 eth0
10.20.20.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0

#添加静态路由和iptables规则
在各宿主机添加静态路由,网关指向对方宿主机的IP
==================================================================
#在第一台宿主机添加静态路由和iptables规则
#添加路由
[root@node1 ~]# route add -net 10.20.20.0/24 gw 192.168.100.203
#修改iptables规则
[root@node1 ~]# iptables -A FORWARD -s 192.168.100.0/24 -j ACCEPT
#或者修改FORWARD默认规则#iptables -P FORWARD ACCEPT
==================================================================
# 在第二台宿主机添加静态路由和iptables规则
[root@DY-Ubuntu-03 ~]#route add -net 10.10.10.0/24 gw 192.168.100.102
[root@DY-Ubuntu-03 ~]#iptables -A FORWARD -s 192.168.100.0/24 -j ACCEPT

#测试跨宿主机之间容器互联
宿主机A的容器server1访问宿主机B容器server2,同时在宿主机B上tcpdump抓包观察
/ # ping 10.20.20.2 -c1
PING 10.20.20.2 (10.20.20.2): 56 data bytes
64 bytes from 10.20.20.2: seq=0 ttl=62 time=1.642 ms


/ # ping -c1 10.10.10.2
PING 10.10.10.2 (10.10.10.2): 56 data bytes
64 bytes from 10.10.10.2: seq=0 ttl=62 time=4.152 ms

#宿主机B的抓包可以观察到
[root@DY-Ubuntu-03 ~]#tcpdump -i enp1s0 -nn icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp1s0, link-type EN10MB (Ethernet), capture size 262144 bytes
14:19:31.083953 IP 192.168.100.102 > 10.20.20.2: ICMP echo request, id 11, seq 0, length 64
14:19:31.086103 IP 10.20.20.2 > 192.168.100.102: ICMP echo reply, id 11, seq 0, length 64

#创建第三个容器测试

#在第二个宿主机B上启动第一个提供web服务的nginx容器server3
#注意无需打开端口映射
[root@DY-Ubuntu-03 ~]#docker run -it -d -p 80:80 --name nginx nginx
[root@DY-Ubuntu-03 ~]#docker exec -it server3 hostname -i
10.20.20.3
==============================================================================
#从server1中访问server3的页面可以成功
/ # wget -qO - http://10.20.20.3
......
<h1>Welcome to nginx!</h1>
......

七、容器单机编排工具 Docker Compose

当在宿主机启动较多的容器时候,如果都是手动操作会觉得比较麻烦而且容易出错,此时推荐使用docker 单机编排工具 docker-compose docker-compose 是 docker 容器的一种单机编排服务,docker-compose 是一个管理多个容器的工具,比如: 可以解决容器之间的依赖关系,就像启动一个nginx 前端服务的时候会调用后端的tomcat,那就得先启动tomcat,但是启动tomcat 容器还需要依赖数据库,那就还得先启动数据库,docker-compose 可以用来解决这样的嵌套依赖关系,并且可以替代docker命令对容器进行创建、启动和停止等手工的操作 因此,如果说docker命令就像linux的命令,docker compose就像shell脚本,可以自动的执行容器批量操作,从而实现自动化的容器管理,或者说docker命令相当于ansible命令,那么docker compose文件,就相当于ansible-playbook的yaml文件 docker-compose 项目是Docker 官方的开源项目,负责实现对Docker 容器集群的快速编排,docker-compose 将所管理的容器分为三层,分别是工程(project),服务(service)以及容器(container)

github地址: ​​https://github.com/docker/compose​​

官方地址: ​​https://docs.docker.com/compose/​​

7-1、安装Docker Compose
7-1-1、 在线安装,通过pip安装

python-pip 包将安装一个 pip 的命令,pip 命令是一个python 安装包的安装工具,其类似于ubuntu 的apt 或者 redhat 的yum,但是pip 只安装 python 相关的安装包,可以在多种操作系统安装和使用pip

此方式当前安装的版本较新,为docker_compose-1.29.2,推荐使用

#centos
[root@node1 ~]# yum install -y python3-pip
[root@node1 ~]# mkdir ~/.pip
[root@node1 ~]# vim ~/.pip/pip.conf
[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple

[root@node1 ~]# docker-compose --version
docker-compose version 1.29.2, build unknown
#期间遇到的问题:
ModuleNotFoundError: No module named 'setuptools_rust'
解决方法:
[root@node1 ~]# pip3 install -U pip setuptools

#ubuntu
[root@DY-Ubuntu-03 ~]#apt install python3-pip
[root@DY-Ubuntu-03 ~]#mkdir ~/.pip
[root@DY-Ubuntu-03 ~]#cat > ~/.pip/pip.conf <<EOF
> [global]
> index-url = https://pypi.tuna.tsinghua.edu.cn/simple
> EOF
[root@DY-Ubuntu-03 ~]#apt -y install python3-pip
Reading package lists... Done
Building dependency tree
Reading state information... Done
python3-pip is already the newest version (20.0.2-5ubuntu1.6).
0 upgraded, 0 newly installed, 0 to remove and 46 not upgraded.
[root@DY-Ubuntu-03 ~]#pip3 install docker-compose

7-2、 在线直接从包仓库安装

#此方法安装的版本较旧,不推荐使用

#centos 8.6以上已经没有此包了

#ubuntu
[root@DY-Ubuntu-03 ~]#apt install docker-compose

7-3、离线安装

直接从github或国内镜像站下载安装对应版本

参看说明: ​​https://github.com/docker/compose/releases​​

\#从国内镜像站下载 ​​https://get.daocloud.io/​​

此方法安装版本可方便指定,推荐方法,但网络下载较慢

curl -L https://github.com/docker/compose/releases/download/1.25.3/docker-compose-`uname
-s`-`uname -m` -o /usr/local/bin/docker-compose
#从国内镜像站下载
curl -L https://get.daocloud.io/docker/compose/releases/download/1.25.3/docker-
compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose

mv docker-compose-linux-x86_64-v2.12.0 /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

[root@node1 ~]# docker-compose --version
Docker Compose version v2.12.0

7-4、查看命令格式

官方文档: ​​https://docs.docker.com/compose/reference/​​

docker-compose --help
Define and run multi-container applications with Docker.
Usage:
docker-compose [-f <arg>...] [options] [COMMAND] [ARGS...]
docker-compose -h|--help
#选项说明:
-f,–file FILE #指定Compose 模板文件,默认为docker-compose.yml
-p,–project-name NAME #指定项目名称,默认将使用当前所在目录名称作为项目名。
--verbose #显示更多输出信息
--log-level LEVEL #定义日志级别 (DEBUG, INFO, WARNING, ERROR, CRITICAL)
--no-ansi #不显示ANSI 控制字符
-v, --version #显示版本
#以下为命令选项,需要在docker-compose.yml|yaml 文件所在在目录里执行
config -q #查看当前配置,没有错误不输出任何信息
up #创建并启动容器
build #构建镜像
bundle #从当前docker compose 文件生成一个以<当前目录>为名称的json格式的Docker Bundle 备
份文件
create #创建服务
down #停止和删除所有容器、网络、镜像和卷
events #从容器接收实时事件,可以指定json 日志格式
exec #进入指定容器进行操作
help #显示帮助细信息
images #显示镜像信息
kill #强制终止运行中的容器
logs #查看容器的日志
pause #暂停服务
port #查看端口
ps #列出容器
pull #重新拉取镜像,镜像发生变化后,需要重新拉取镜像
push #上传镜像
restart #重启服务
rm #删除已经停止的服务
run #一次性运行容器
scale #设置指定服务运行的容器个数,新版已废弃
start #启动服务
stop #停止服务
top #显示容器运行状态
unpause #取消暂定

7-5、docker compose 文件格式

官方文档: ​​https://docs.docker.com/compose/compose-file/​​

docker compose 文件是一个yaml格式的文件,所以注意行首的缩进很严格

默认docker-compose命令会调用当前目录下的docker-compose.yml的文件,因此一般执行docker-compose命令前先进入docker-compose.yml文件所在目录

docker compose文件的格式很不同版本,版本不同,语法和格式有所不同

7-6、实现 Wordpress 应用

[root@node1 wordpress]# vim docker-compose.yml
version: '3'

services:
db:
image: mysql:8.0
container_name: db
restart: unless-stopped
environment:
- MYSQL_ROOT_PASSWORD=123456
- MYSQL_DATABASE=wordpress
- MYSQL_USER=wordpress
- MYSQL_PASSWORD=123456
volumes:
- dbdata:/var/lib/mysql
networks:
- wordpress-network

wordpress:
depends_on:
- db
image: wordpress:php7.4-apache
container_name: wordpress
restart: unless-stopped
ports:
- "80:80"
environment:
- WORDPRESS_DB_HOST=db:3306
- WORDPRESS_DB_USER=wordpress
- WORDPRESS_DB_PASSWORD=123456
- WORDPRESS_DB_NAME=wordpress

volumes:
- wordpress:/var/www/html
networks:
- wordpress-network

volumes:
wordpress:
dbdata:

networks:
wordpress-network:
driver: bridge
ipam:
config:
- subnet: 10.10.20.0/24

7-7、搭建运维平台 Spug

[root@node1 spug]# vim docker-compose.yml 
version: '3.2.4'

services:
db:
image: mariadb:10.8
container_name: spug-db
restart: always
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
volumes:
- /data/spug/mysql:/var/lib/mysql
environment:
- MYSQL_DATABASE=spug
- MYSQL_USER=spug
- MYSQL_PASSWORD=spug.cc
- MYSQL_ROOT_PASSWORD=spug.cc
spug:
image: openspug/spug-service
container_name: spug
privileged: true
restart: always
volumes:
- /data/spug/service:/data/spug
- /data/spug/repos:/data/repos
ports:
- "80:80"
environment:
- SPUG_DOCKER_VERSION=v3.2.4
- MYSQL_DATABASE=spug
- MYSQL_USER=spug
- MYSQL_PASSWORD=spug.cc
- MYSQL_HOST=db
- MYSQL_PORT=3306
depends_on:
- db

#启动项目
[root@node1 spug]# docker-compose up

#初始化:以下操作会创建一个用户名为 admin 密码为 spug.dev 的管理员账户,可自行替换管理员账户/密码。
[root@node1 spug]# docker exec spug init_spug admin spug.dev

#访问测试:在浏览器中输入 http://192.168.100.102访问(默认账户密码在上面一步初始化时设置)。

7-8、一键生成 docker-compose.yml网站

利用网站将docker 命令自动生成 Docker Compse

https://www.composerize.com/

Docker从入门到精通_ubuntu_11

八、Docker 仓库管理

Docker仓库,类似于yum仓库,是用来保存镜像的仓库。为了方便的管理和使用docker镜像,可以将镜像集中保存至Docker仓库中,将制作好的镜像push到仓库集中保存,在需要镜像时,从仓库中pull镜像即可。

Docker 仓库分为公有云仓库和私有云仓库

公有云仓库: 由互联网公司对外公开的仓库

  • 官方
  • 阿里云等第三方仓库

私有云仓库: 组织内部搭建的仓库,一般只为组织内部使用,常使用下面软件搭建仓库

  • docker registory
  • docker harbor
8-1、官方 Docker 仓库

将自制的镜像上传至docker仓库;​​https://hub.docker.com/​​

8-1-1、注册账户

访问hub.docker.com注册账户,并登录

Docker从入门到精通_docker_12

8-1-2、使用用户仓库管理镜像

每个注册用户都可以上传和管理自已的镜像

#用户登录
#方法一:
[root@node1 spug]# docker login
Login with your Docker ID 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.
Username: dayuwang
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/#credentials-store

Login Succeeded
======
#方法二:
[root@node1 spug]# docker login -u dayuwang -p Wdy-111111 docker.io
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
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/#credentials-store

Login Succeeded

#登录成功后,在家目录自动生成验证信息,下次会自动登录,而无需手动登录
[root@node1 ~]# cat .docker/config.json
{
"auths": {
"harbor103.org": {
"auth": "YWRtaW46MTIzNDU2"
},
"https://index.docker.io/v1/": {
"auth": "ZGF5dXdhbmc6V2R5QDI5MTIwMDY="
}
}
}

#给本地镜像打标签
上传本地镜像前必须先给上传的镜像用docker tag 命令打标签
标签格式: docker.io/用户帐号/镜像名:TAG

[root@node1 ~]# docker tag alpine:v3.15 docker.io/dayuwang/alpine:v3.15

#上传本地镜像至官网
[root@node1 ~]# docker push docker.io/dayuwang/alpine:v3.15

在官网验证上传的镜像

Docker从入门到精通_ubuntu_13

下载上传的镜像并创建容器

#在另一台主机上下载镜像
[root@DY-Ubuntu-03 ~]#docker pull dayuwang/alpine:v3.15
[root@DY-Ubuntu-03 ~]#docker run -it dayuwang/alpine:v3.15 sh
/ # cat /etc/issue
Welcome to Alpine Linux 3.16
Kernel \r on an \m (\l)

8-1-3、使用组织管理镜像

组织类似于名称空间,每个组织的名称全网站唯一,一个组织可以有多个用户帐户使用,并且可以指定不同用户对组织内的仓库不同的权限(注意注意注意:这个数需要money)

三种不同权限

  • Read-only: Pull and view repository details and builds
  • Read &Write: Pull, push, and view a repository; view, cancel, retry or trigger builds
  • Admin: Pull, push, view, edit, and delete a repository; edit build settings; update therepository description
8-2、阿里云Docker仓库
8-2-1、注册和登录阿里云仓库

用浏览器访问​​​http://cr.console.aliyun.com​​

Docker从入门到精通_ubuntu_14

8-2-2、创建仓库

此步可不事先执行,docker push 时可以自动创建私有仓库

Docker从入门到精通_docker_15

Docker从入门到精通_ubuntu_16

Docker从入门到精通_docker_17

Docker从入门到精通_docker_18

Docker从入门到精通_ubuntu_19

Docker从入门到精通_nginx_20

8-2-3、上传镜像前先登录阿里云

[root@DY-Ubuntu-03 ~]#docker login --username=135****5070 registry.cn-zhangjiakou.aliyuncs.com/dayuwang/alpine
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/#credentials-store

Login Succeeded

8-2-4、打标签并上传

[root@DY-Ubuntu-03 ~]#docker tag alpine:v3.15 registry.cn-zhangjiakou.aliyuncs.com/dayuwang/alpine
[root@DY-Ubuntu-03 ~]#docker push registry.cn-zhangjiakou.aliyuncs.com/dayuwang/alpine
Using default tag: latest
The push refers to repository [registry.cn-zhangjiakou.aliyuncs.com/dayuwang/alpine]
8d3ac3489996: Pushed
latest: digest: sha256:e7d88de73db3d3fd9b2d63aa7f447a10fd0220b7cbf39803c803f2af9ba256b3 size: 528

Docker从入门到精通_docker_21

8-2-5、另一台主机下载并运行容器

[root@node1 ~]# docker pull registry.cn-zhangjiakou.aliyuncs.com/dayuwang/alpine
[root@node1 ~]# docker run -it --rm registry.cn-zhangjiakou.aliyuncs.com/dayuwang/alpine sh

8-3、私有云单机仓库Docker Registry
8-3-1、 Docker Registry 介绍

Docker Registry作为Docker的核心组件之一负责单主机的镜像内容的存储与分发,客户端的docker pull以及push命令都将直接与registry进行交互,最初版本的registry 由Python实现,由于设计初期在安全性,性能以及API的设计上有着诸多的缺陷,该版本在0.9之后停止了开发,由新项目distribution(新的docker register被称为Distribution)来重新设计并开发下一代registry,新的项目由go语言开发,所有的API,底层存储方式,系统架构都进行了全面的重新设计已解决上一代registry中存在的问题,2016年4月份registry 2.0正式发布,docker 1.6版本开始支持registry 2.0,而八月份随着docker 1.8 发布,docker hub正式启用2.1版本registry全面替代之前版本 registry,新版registry对镜像存储格式进行了重新设计并和旧版不兼容,docker 1.5和之前的版本无法读取2.0的镜像,另外,Registry 2.4版本之后支持了回收站机制,也就是可以删除镜像了,在2.4版本之前是无法支持删除镜像的,所以如果你要使用最好是大于Registry 2.4版本的

官方文档地址: ​​https://docs.docker.com/registry/​​​ 官方github 地址: ​​​https://github.com/docker/distribution​​​ 官方部署文档: ​​​https://github.com/docker/docker.github.io/blob/master/registry/deploying.md​​

8-3-2、docker registry搭建本地私有仓库

Docker从入门到精通_nginx_22

#下载 docker registry 镜像
[root@node2 ~]# docker pull registry:2.8.1

#创建授权用户密码使用目录
[root@node2 ~]# mkdir -p /etc/docker/auth

#创建授权的registry用户和密码,用于上传和下载镜像
[root@node2 ~]# yum install -y httpd-tools
[root@node2 ~]# htpasswd -Bbn wang 123456 > /etc/docker/auth/registry
[root@node2 ~]# cat /etc/docker/auth/registry
wang:$2y$05$0e74x8AeLKQ2gDB3kXxaceiN5HZUQto9hl1Iu0wGnGmihOf5TFWOi

#启动docker registry 容器
[root@node2 ~]# docker run -d -p 5000:5000 --restart=always --name registry-distribution -v /etc/docker/auth:/auth -e "REGISTRY_AUTH=htpasswd" -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/registry registry:2.8.1
eb2e75419275c36d3e09fab4a3d09e67187333ae9b3439c132e7608a3a0ff436

#直接登录报错
[root@node1 ~]# docker login 192.168.100.103:5000
Username: wang
Password:
Error response from daemon: Get "https://192.168.100.103:5000/v2/": http: server gave HTTP response to HTTPS client
#docker login 默认使用https登录,而docker registry为http,所以默认登录失败

# 修改配置让docker login支持http协议 方法1:
[root@node1 ~]# vim /etc/docker/daemon.json

{
"registry-mirrors": ["https://pgavrk5n.mirror.aliyuncs.com"],
"insecure-registries": ["192.168.100.103:5000"]
}
[root@node1 ~]# systemctl restart docker

# 修改配置让docker login支持http协议 方法2:
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --insecure-registry 192.168.100.103:5000
[root@node1 ~]# systemctl daemon-reload
[root@node1 ~]# systemctl restart docker

# 再次登录验证成功
[root@node1 ~]# docker login 192.168.100.103:5000
Username: wang
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/#credentials-store

Login Succeeded

#打标签并上传镜像
[root@node1 ~]# docker tag alpine:v3.15 192.168.100.103:5000/alpine:v3.15
[root@node1 ~]# docker push 192.168.100.103:5000/alpine:v3.15
The push refers to repository [192.168.100.103:5000/alpine]
994393dc58e7: Pushed
v3.15: digest: sha256:1304f174557314a7ed9eddb4eab12fed12cb0cd9809e4c28f29af86979a3c870 size: 528

#下载镜像并启动容器
[root@DY-Ubuntu-03 ~]#vim /usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H unix://var/run/docker.sock --insecure-registry 192.168.100.103:5000

[root@DY-Ubuntu-03 ~]#systemctl daemon-reload
[root@DY-Ubuntu-03 ~]#systemctl restart docker.servic

[root@DY-Ubuntu-03 ~]#docker login 192.168.100.103:5000
Username: wang
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/#credentials-store

Login Succeeded

[root@DY-Ubuntu-03 ~]#docker pull 192.168.100.103:5000/alpine:v3.15
v3.15: Pulling from alpine
Digest: sha256:1304f174557314a7ed9eddb4eab12fed12cb0cd9809e4c28f29af86979a3c870
Status: Downloaded newer image for 192.168.100.103:5000/alpine:v3.15
192.168.100.103:5000/alpine:v3.15

[root@DY-Ubuntu-03 ~]#docker run -it --rm 192.168.100.103:5000/alpine:v3.15

8-4、Docker 之分布式仓库 Harbor
8-4-1、Harbor 介绍

Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器,由VMware开源,其通过添加一些企业必需的功能特性,例如安全、标识和管理等,扩展了开源 Docker Distribution。作为一个企业级私有Registry服务器,Harbor 提供了更好的性能和安全。提升用户使用Registry构建和运行环境传输镜像的效率。Harbor支持安装在多个Registry节点的镜像资源复制,镜像全部保存在私有 Registry 中, 确保数据和知识产权在公司内部网络中管控,另外,Harbor也提供了高级的安全特性,诸如用户管理,访问控制和活动审计等

vmware 官方开源服务: ​​https://vmware.github.io/​​​ harbor 官方github 地址: ​​​https://github.com/vmware/harbor​​

harbor 官方网址: ​​https://goharbor.io/​​​ harbor 官方文档: ​​​https://goharbor.io/docs/​​​ github文档: ​​​https://github.com/goharbor/harbor/tree/master/docs​​

基于角色的访问控制: 用户与Docker镜像仓库通过“项目”进行组织管理,一个用户可以对多个镜像仓库在同一命名空间(project)里有不同的权限
镜像复制: 镜像可在多个Registry实例中复制(同步)。尤其适合于负载均衡,高可用,混合云和多云的场景
图形化用户界面: 用户可以通过浏览器来浏览,检索当前Docker镜像仓库,管理项目和命名空间
AD/LDAP支持: Harbor可以集成企业内部已有的AD/LDAP,用于鉴权认证管理
审计管理: 所有针对镜像仓库的操作都可以被记录追溯,用于审计管理
国际化: 已拥有英文、中文、德文、日文和俄文的本地化版本。更多的语言将会添加进来
RESTful API: 提供给管理员对于Harbor更多的操控, 使得与其它管理软件集成变得更容易
部署简单: 提供在线和离线两种安装工具, 也可以安装到vSphere平台(OVA方式)虚拟设备

- Proxy: 对应启动组件nginx。它是一个nginx反向代理,代理Notary client(镜像认证)、Docker client(镜像上传下载等)和浏览器的访问请求(Core Service)给后端的各服务
- UI(Core Service): 对应启动组件harbor-ui。底层数据存储使用mysql数据库,主要提供了四个子功能:
UI: 一个web管理页面ui
API: Harbor暴露的API服务
Auth: 用户认证服务,decode后的token中的用户信息在这里进行认证;auth后端可以接db、ldap、uaa三种认证实现
Token服务(上图中未体现): 负责根据用户在每个project中的role来为每一个dockerpush/pull命令发布一个token,如果从docker client发送给registry的请求没有带token,registry会重定向请求到token服务创建token
- Registry: 对应启动组件registry。负责存储镜像文件,和处理镜像的pull/push命令。Harbor对镜像进行强制的访问控制,Registry会将客户端的每个pull、push请求转发到token服务来获取有效的token
- Admin Service: 对应启动组件harbor-adminserver。是系统的配置管理中心附带检查存储用量,ui和jobserver启动时候需要加载adminserver的配置
- Job Sevice: 对应启动组件harbor-jobservice。负责镜像复制工作的,他和registry通信,从一个registry pull镜像然后push到另一个registry,并记录job_log
- Log Collector: 对应启动组件harbor-log。日志汇总组件,通过docker的log-driver把日志汇总到一起
- DB: 对应启动组件harbor-db,负责存储project、 user、 role、replication、image_scan、access等的metadata数据

8-4-2、安装 Harbor

下载地址: ​​https://github.com/vmware/harbor/releases​​​ 安装文档: ​​​https://github.com/goharbor/harbor/blob/master/docs/install-config/_index.md​​

环境准备: 共四台主机 两台harbor服务器,地址: 10.0.0.101|18 两台harbor客户端,用于上传和下载镜像 ,地址: 10.0.0.102|28

#安装docker(10.0.0.101、10.0.0.18)
[root@rocky8 ~]#bash docker_install.sh
[root@rocky8 ~]#docker --version
Docker version 20.10.19, build d85ef84

#安装docker compose(10.0.0.101、10.0.0.18)
[root@rocky8 ~]#mv docker-compose-linux-x86_64-v2.12.0 /usr/local/bin/docker-compose
[root@rocky8 ~]#chmod +x /usr/local/bin/docker-compose
[root@rocky8 ~]#docker-compose --version
Docker Compose version v2.12.0

#下载Harbor安装包并解压缩(10.0.0.101、10.0.0.18)
https://github.com/goharbor/harbor/releases
[root@rocky8 ~]#mkdir /apps
[root@rocky8 ~]#tar xf harbor-offline-installer-v2.6.1.tgz -C /apps/

#编辑 harbor 配置文件(10.0.0.101、10.0.0.18)
[root@rocky8 ~]#mv /apps/harbor/harbor.yml.tmpl /apps/harbor/harbor.yml
[root@rocky8 ~]#vim /apps/harbor/harbor.yml
hostname: 10.0.0.18 #修改此行,指向当前主机IP 或 FQDN,建议配置IP
#注意: 第二台服务器配置 hostname = 10.0.0.101
harbor_admin_password: 123456 #修改此行指定harbor登录用户admin的密码,默认用户/密码:admin/Harbor12345
==========================================
#可选项
data_volume: /data/harbor #指定存放数据的目录,建议放在独立的大容量快速磁盘或存储上
ui_url_protocol = http #默认即可,如果修改为https,需要指定下面证书路径
ssl_cert = /data/cert/server.crt #默认即可,https时,需指定下面证书文件路径
ss_cert_key = /data/cert/server.key #默认即可,https时,需指定下面私钥文件路径

#运行 harbor 安装脚本(10.0.0.101、10.0.0.18)
[root@rocky8 ~]#yum install python3 -y #先安装python

[root@rocky8 ~]#/apps/harbor/install.sh #运行 harbor 安装脚本
......
[Step 5]: starting Harbor ...
[+] Running 10/10
⠿ Network harbor_harbor Created 0.1s
⠿ Container harbor-log Started 0.8s
⠿ Container registry Started 5.5s
⠿ Container harbor-db Started 5.3s
⠿ Container harbor-portal Started 5.1s
⠿ Container registryctl Started 5.4s
⠿ Container redis Started 4.9s
⠿ Container harbor-core Started 6.6s
⠿ Container nginx Started 8.0s
⠿ Container harbor-jobservice Started 8.1s
----Harbor has been installed and started successfully.----

#注:如果中途提示错误:ERROR:root:Error: The protocol is https but attribute ssl_cert is not set 把harbor.yml里的https项注释即可

#设置开机自动启动 harbor(10.0.0.101、10.0.0.18)
#方法1:通过service文件实现(前提是docker服务自启动)
[root@rocky8 ~]#vim /lib/systemd/system/harbor.service
[root@rocky8 ~]#vim /usr/lib/systemd/system/harbor.service

[Unit]
Description=Harbor
After=docker.service systemd-networkd.service systemd-resolved.service
Requires=docker.servcie
Documentation=http://github.com/vmware/harbor

[Service]
Type=simple
Restart=on-faliure
RestartSec=5
ExecStart=/usr/local/bin/docker-compose -f /apps/harbor/docker-compose.yml up #注意docker-compose的路径
ExecStop=/usr/local/bin/docker-compose -f /apps/harbor/docker-compose.yml down

[Install]
WantedBy=multi-user.target

[root@rocky8 ~]#systemctl daemon-reload
[root@rocky8 ~]#systemctl enable harbor.service

浏览器访问ip即可登陆

Docker从入门到精通_docker_23

8-4-3、使用单主机 Harbor

harbor上必须先建立项目,才能上传镜像

#客户端命令行登录 harbor(10.0.0.28)
[root@rocky8 ~]#vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://pgavrk5n.mirror.aliyuncs.com"],
"insecure-registries": ["10.0.0.18", "10.0.0.101"]
}

[root@rocky8 ~]#systemctl restart docker.service

[root@rocky8 ~]#docker login 10.0.0.18
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/#credentials-store

Login Succeeded
[root@rocky8 ~]#cat .docker/config.json
{
"auths": {
"10.0.0.18": {
"auth": "YWRtaW46MTIzNDU2"
}
}
}

#镜像打标签并上传到 Harbor(10.0.0.28)
不修改成指定格式无法将镜像上传到 harbor 仓库 Harbor主机IP/项目名/image名:版本

[root@rocky8 ~]#docker tag alpine 10.0.0.18/test/alpine:v3.15
[root@rocky8 ~]#docker push 10.0.0.18/test/alpine:v3.15 ##上传镜像前,必须先登录harbor
The push refers to repository [10.0.0.18/test/alpine]
8d3ac3489996: Pushed
v3.15: digest: sha256:e7d88de73db3d3fd9b2d63aa7f447a10fd0220b7cbf39803c803f2af9ba256b3 size: 528
#注:如果不事先建立项目,上传镜像失败

Docker从入门到精通_ubuntu_24

#另一客户端下载 Harbor 的镜像(10.0.0.102):
[root@ubuntu2004 ~]#vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://pgavrk5n.mirror.aliyuncs.com"],
"insecure-registries": ["10.0.0.18", "10.0.0.101"]
}
[root@ubuntu2004 ~]#systemctl restart docker.service

[root@ubuntu2004 ~]#docker login 10.0.0.18
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/#credentials-store

Login Succeeded

[root@ubuntu2004 ~]#docker pull 10.0.0.18/test/alpine:v3.15
v3.15: Pulling from test/alpine
59bf1c3509f3: Pull complete
Digest: sha256:e7d88de73db3d3fd9b2d63aa7f447a10fd0220b7cbf39803c803f2af9ba256b3
Status: Downloaded newer image for 10.0.0.18/test/alpine:v3.15
10.0.0.18/test/alpine:v3.15

[root@ubuntu2004 ~]#docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
10.0.0.18/test/alpine v3.15 c059bfaa849c 10 months ago 5.59MB

# 注:后期如果修改harbor配置,比如: 修改IP地址等,可执行以下步骤生效
docker-compose stop #停止容器
vim harbor.cfg #修改harbor配置
/apps/harbor/prepare #更新配置
docker-compose start #重新启动docker compose

# 或者:
#/apps/harbor/install.sh

8-4-4、实现 Harbor 高可用

Harbor支持基于策略的Docker镜像复制功能,这类似于MySQL的主从同步,其可以实现不同的数据中心、不同的运行环境之间同步镜像,并提供友好的管理界面,大大简化了实际运维中的镜像管理工作,已经有用很多互联网公司使用harbor搭建内网docker仓库的案例,并且还有实现了双向复制功能

登陆第二台服务器:10.0.0.101

第二台harbor上新建项目

参考第一台harbor服务器的项目名称,在第二台harbor服务器上新建与之同名的项目

输入第一台harbor服务器上的主机10.0.0.101,目标名(即项目名)test和用户信息及密码admin

Docker从入门到精通_docker_25

Docker从入门到精通_ubuntu_26

Docker从入门到精通_docker_27

第二台harbor上新建复制规则实现到第一台harbor的单向复制

在第二台harbor上建立复制的目标主机,将第二台harbor上面的镜像复制到第一台harbor上

Docker从入门到精通_docker_28

Docker从入门到精通_ubuntu_29

在第一台harbor主机上重复上面操作

以上操作,只是实现了从第二台harbor主机10.0.0.102到第一台harbor主机10.0.101的单向同步在第一台harbor上再执行下面操作,才实现双向同步

上传镜像观察是否可以双高同步

[root@ubuntu2004 ~]#docker tag busybox 10.0.0.18/test/busybox:v1.1.1
[root@ubuntu2004 ~]#docker push 10.0.0.18/test/busybox:v1.1.1
The push refers to repository [10.0.0.18/test/busybox]
01fd6df81c8e: Pushed
v1.1.1: digest: sha256:62ffc2ed7554e4c6d360bce40bbcf196573dd27c4ce080641a2c59867e732dee size: 527

Docker从入门到精通_ubuntu_30

Docker从入门到精通_ubuntu_31

#配置 Nginx 做为反向代理(10.0.0.38):
[root@rocky8 ~]#vim /apps/nginx/conf/conf.d/harbor.wang.org.conf

upstream harbor {
ip_hash;
server harbor1.wang.org;
server harbor2.wang.org;
}

server {
listen 80;
server_name harbor.wang.org;
client_max_body_size 10g;
location / {
proxy_pass http://harbor;
}
}
[root@rocky8 ~]#systemctl restart nginx.service

[root@rocky8 ~]#vim /etc/hosts
10.0.0.18 harbor1.wang.org
10.0.0.101 harbor2.wang.org

#客户端配置:(10.0.0.28、10.0.0.102):
[root@rocky8 ~]#vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://pgavrk5n.mirror.aliyuncs.com"],
"insecure-registries": ["harbor.wang.org"]
}

[root@rocky8 ~]#systemctl restart docker.service
[root@rocky8 ~]#vim /etc/hosts
10.0.0.38 harbor.wang.org

# 测试上传
[root@rocky8 ~]#docker login harbor.wang.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/#credentials-store

Login Succeeded
[root@rocky8 ~]#docker push harbor.wang.org/test/nginx:v1.1.2
The push refers to repository [harbor.wang.org/test/nginx]
d874fd2bc83b: Pushed
32ce5f6a5106: Pushed
f1db227348d0: Pushed
b8d6e692a25e: Pushed
e379e8aedd4d: Pushed
2edcec3590a4: Pushed
v1.1.2: digest: sha256:ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0bfd5c4c20a2fa2aaa7ede3 size: 1570

8-4-5、Harbor 安全 Https 配置(此项用在局域网内可以不用,使用nginx的https替换,如8-4-6)

基于安全考虑,生产建议采用 https 代替 http

#实现 Harbor 的 Https 认证

# 生成 Harbor 服务器证书
[root@rocky8 ~]#mkdir /data/cert
[root@rocky8 ~]#cd /data/cert
[root@rocky8 cert]#ls
[root@rocky8 cert]#openssl genrsa -out ca.key 4096

#生成ca的自签名证书
[root@rocky8 cert]#openssl req -x509 -new -nodes -sha512 -days 3650 -subj "/C=CN/ST=Beijing/L=Beijing/O=test/OU=wang/CN=wang.org" -key ca.key -out ca.crt

#生成harbor主机的私钥
[root@rocky8 cert]#openssl genrsa -out harbor.wang.org.key 4096

#生成harbor主机的证书申请
[root@rocky8 cert]#openssl req -sha512 -new \
> -subj "/C=CN/ST=Beijing/L=Beijing/O=test/OU=wang/CN=wang.org" \
> -key harbor.wang.org.key \
> -out harbor.wang.org.csr

#创建x509 v3 扩展文件(新版新增加的要求)
[root@rocky8 cert]#cat > v3.ext <<EOF
> authorityKeyIdentifier=keyid,issuer
> basicConstraints=CA:FALSE
> keyUsage=digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
> extendedKeyUsage=serverAuth
> subjectAltName=@alt_names
> [alt_names]
> DNS.1=wang.org
> DNS.2=wang
> DNS.3=harbor.wang.org
> EOF

#给 harbor主机颁发证书
[root@rocky8 cert]#openssl x509 -req -sha512 -days 3650 -extfile v3.ext -CA ca.crt -CAkey ca.key -CAcreateserial -in harbor.wang.org.csr -out harbor.wang.org.crt
Signature ok
subject=C = CN, ST = Beijing, L = Beijing, O = test, OU = wang, CN = wang.org
Getting CA Private Key

[root@rocky8 cert]#ls
ca.crt ca.key ca.srl harbor.wang.org.crt harbor.wang.org.csr harbor.wang.org.key v3.ext

注意: 如果不生成创建x509 v3 扩展文件,会出现下面提示错误

docker login harbor.wang.org
Username: admin
Password:
Error response from daemon: Get "https://harbor.wang.org/v2/": x509: certificate
relies on legacy Common Name field, use SANs or temporarily enable Common Name
matching with GODEBUG=x509ignoreCN=0

8-4-6、nginx实现https加密

[root@rocky8 ~]#mkdir /apps/nginx/conf/certs
[root@rocky8 ~]#cd /apps/nginx/conf/certs
[root@rocky8 certs]#openssl req -newkey rsa:4096 -nodes -sha256 -keyout ca.key -x509 -days 2650 -out ca.crt
[root@rocky8 certs]#openssl req -newkey rsa:4096 -nodes -sha256 -keyout harbor.wang.org.key -out harbor.wang.org.csr
[root@rocky8 certs]#openssl x509 -req -days 3650 -in harbor.wang.org.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out harbor.wang.org.crt
[root@rocky8 certs]#openssl x509 -in harbor.wang.org.crt -noout -text
[root@rocky8 certs]#cat harbor.wang.org.crt ca.crt > harbor.wang.org.pem

[root@rocky8 certs]#vim /apps/nginx/conf/conf.d/harbor.wang.org.conf
upstream harbor {
hash $remote_addr;
server harbor1.wang.org;
server harbor2.wang.org;
}

server {
listen 80;
server_name harbor.wang.org;
return 302 https://$server_name$request_uri;

}


server {
listen 443 ssl http2;
ssl_certificate /apps/nginx/conf/certs/harbor.wang.org.pem;
ssl_certificate_key /apps/nginx/conf/certs/harbor.wang.org.key;
ssl_session_cache shared:sslcache:20m;
ssl_session_timeout 10m;
server_name harbor.wang.org;
client_max_body_size 10g;
location / {
proxy_pass http://harbor;
}
}

[root@rocky8 certs]#nginx -t
[root@rocky8 certs]#nginx -s reload

Docker从入门到精通_nginx_32

Docker从入门到精通_ubuntu_33

九、Docker 的资源限制
9-1、OOM (Out of Memory Exception)

对于 Linux 主机,如果没有足够的内存来执行其他重要的系统任务,将会抛出OOM (Out of MemoryException,内存溢出、内存泄漏、内存异常 ),随后系统会开始杀死进程以释放内存, 凡是运行在宿主机的进程都有可能被 kill ,包括 Dockerd和其它的应用程序, 如果重要的系统进程被 Kill,会导致和该进程相关的服务全部宕机。通常越消耗内存比较大的应用越容易被kill,比如: MySQL数据库,Java程序等

产生 OOM 异常时, Dockerd尝试通过调整 Docker 守护程序上的 OOM 优先级来减轻这些风险,以便它比系统上的其他进程更不可能被杀死但是每个容器 的 OOM 优先级并未调整, 这使得单个容器被杀死的可能性比 Docker守护程序或其他系统进程被杀死的可能性更大,不推荐通过在守护程序或容器上手动设置-- oom -score-adj为极端负数,或通过在容器上设置 -- oom-kill-disable来绕过这些安全措施

OOM 优先级机制: linux会为每个进程计算一个分数,最终将分数最高的kill

/proc/PID/oom_score_adj
#范围为 -1000 到 1000,值越高容易被宿主机 kill掉,如果将该值设置为 -1000 ,则进程永远不会被宿主机 kernel kill
/proc/PID/oom_adj
#范围为 -17 到+15 ,取值越高越容易被干掉,如果是 -17 , 则表示不能被 kill ,该设置参数的存在是为了和旧版本的 Linux 内核兼容。
/proc/PID/oom_score
#这个值是系统综合进程的内存消耗量、 CPU 时间 (utime + 存活时间 (uptime - start time) 和oom_adj 计算出的进程得分 ,消耗内存越多得分越高,容易被宿主机 kernel 强制杀死

9-2、Stress-ng 压力测试工具

stress-ng是一个压力测试工具,可以通过软件仓库进行安装,也提供了docker版本的容器 官方链接:​​https://kernel.ubuntu.com/~cking/stress-ng/​​​ 官方文档:​​​https://wiki.ubuntu.com/Kernel/Reference/stress-ng​​

容器方式安装

docker pull lorel/docker-stress-ng

软件包方式安装

yum -y install stress-ng
apt -y install stress-ng

9-3、容器的内存限制

Docker 可以强制执行硬性内存限制,即只允许容器使用给定的内存大小。 Docker 也可以执行非硬性内存限制,即容器可以使用尽可能多的内存,除非内核检测到主机上的内存不够用了

Docker从入门到精通_nginx_34

9-4、swap限制

docker run 命令可以使用--memory-swap 选项控制swap的使用

--memory-swap #只有在设置了 --memory 后才会有意义。使用 Swap,可以让容器将超出限制部分的内存置换到磁盘上,WARNING: 经常将内存交换到磁盘的应用程序会降低性能

不同的--memory-swap 设置会产生不同的效果:

Docker从入门到精通_ubuntu_35

-memory-swap #值为正数, 那么--memory 和--memory-swap 都必须要设置,--memory-swap 表示你能使用的内存和 swap 分区大小的总和,例如: --memory=300m, --memory-swap=1g, 那么该容器能够使用 300m 物理内存和 700m swap,即--memory 是实际物理内存大小值不变,而 swap 的实际大小计算方式为(--memory-swap)-(--memory)=容器可用 swap
--memory-swap #如果设置为 0,则忽略该设置,并将该值视为未设置,即未设置交换分区
--memory-swap #如果等于--memory 的值,并且--memory 设置为正整数,容器无权访问 swap
-memory-swap #如果未设置,如果宿主机开启了 swap,则实际容器的swap 值最大为 2x( --memory),即两倍于物理内存大小,例如,如果--memory="300m"与--memory-swap没有设置,该容器可以使用300m总的内存和600m交撒空间,但是并不准确(在容器中使用free 命令所看到的 swap 空间并不精确,毕竟每个容器都可以看到具体大小,宿主机的 swap 是有上限的,而且不是所有容器看到的累计大小)
--memory-swap #如果设置为-1,如果宿主机开启了 swap,则容器可以使用主机上 swap 的最大空间

注意: 在容器中执行free命令看到的是宿主机的内存和swap使用,而非容器自身的swap使用情况

9-4-1、 使用stress-ng测试内存限制

假如一个容器未做内存使用限制,则该容器可以利用到系统内存最大空间,默认创建的容器没有做内存资源限制。

#默认一个workers 分配256M内存,2个即占512M内存
[root@rocky8 ~]#docker run --name c1 -it --rm lorel/docker-stress-ng --vm 2
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 2 vm

#因上一个命令是前台执行,下面在另一个终端窗口中执行,可以看到占用512M左右内存
[root@rocky8 ~]#docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
6bbd6c4cc7bd c1 194.97% 516.5MiB / 1.744GiB 28.93% 1.25kB / 0B 0B / 0B 5

#指定内存最大值
[root@rocky8 ~]#docker run --name c1 -it --rm -m 300m lorel/docker-stress-ng --vm 2
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 2 vm

#在另一个终端窗口执行
[root@rocky8 ~]#docker stats --no-stream
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
04e77f8a0eef c1 136.93% 300MiB / 300MiB 99.99% 876B / 0B 4.48GB / 0B 5

举报

相关推荐

0 条评论