1、容器技术
1、安装docker
1.1 准备软件仓库
# 准备软件仓库
[root@rocky ~]# cat /etc/yum.repos.d/Rocky.repo
[BaseOS]
name=BaseOS
baseurl=https://mirrors.aliyun.com/rockylinux/9.2/BaseOS/x86_64/os/
gpgcheck=0
enabled=1
[AppStream]
name=AppStream
baseurl=https://mirrors.aliyun.com/rockylinux/9.2/AppStream/x86_64/os/
gpgcheck=0
enabled=1
[HighAvailability]
name=HighAvailability
baseurl=https://mirrors.aliyun.com/rockylinux/9.2/HighAvailability/x86_64/os/
gpgcheck=0
enabled=1
[EPEL]
name=EPEL
baseurl=https://mirrors.aliyun.com/epel/9/Everything/x86_64/
gpgcheck=0
enabled=1
1.2 安装docker
安装docker,本次实验使用Rocky9作为基础,故默认安装软件为podman-docker
yum -y install docker
查看docker版本
[root@rocky ~]# podman -v
podman version 4.4.1
2、镜像管理
2.1 查找镜像
docker search 镜像名
[root@rocky ~]# docker search rockylinux
2.2 拉取镜像
docker pull 镜像
[root@rocky ~]# docker pull docker.io/library/rockylinux:9
2.3 列出镜像
docker image ls/list
[root@rocky ~]# docker image list
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/dokken/rockylinux-8 latest 652a653ce2a1 15 hours ago 377 MB
docker.io/library/rockylinux 8 4e97feadb276 4 days ago 204 MB
docker.io/library/rockylinux 9 eeea865f4111 4 days ago 181 MB
docker.io/library/nginx latest f9c14fe76d50 6 days ago 147 MB
docker.io/library/ubuntu latest 3b418d7b466a 5 weeks ago 80.3 MB
docker.io/library/centos latest 5d0da3dc9764 20 months ago 239 MB
2.4 给镜像打标签
docker tag 镜像:tag 镜像:新tag
[root@rocky ~]# docker tag docker.io/library/rockylinux:8 docker.io/library/rockylinux:rocky8
2.5 删除镜像
docker rmi 镜像名/镜像ID
[root@rocky ~]# docker rmi docker.io/library/rockylinux:rocky8
Untagged: docker.io/library/rockylinux:rocky8
2.6 导出镜像
docker save 镜像名/镜像ID > 文件
[root@rocky ~]# docker save docker.io/library/rockylinux:9 > rocky9.tar
2.7 导入镜像
docker load -i 镜像文件
# 删除镜像
[root@rocky ~]# docker rmi docker.io/library/rockylinux:9
Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.
Untagged: docker.io/library/rockylinux:9
Deleted: eeea865f4111bd48e16801554f44adf2db2fa4cb87a98ff7470d6de6be49fc15
# 导入镜像
[root@rocky ~]# podman load -i rocky9.tar
Getting image source signatures
Copying blob bb25ee446163 done
Copying config eeea865f41 done
Writing manifest to image destination
Storing signatures
Loaded image: docker.io/library/rockylinux:9
3、容器管理
3.1 查看容器
[root@rocky ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3.2 创建容器
创建一个名为rocky8的容器
[root@rocky ~]# docker run --name rocky8 docker.io/library/rockylinux:8
创建一个长时间运行容器
[root@rocky ~]# docker run -it --name rocky9 docker.io/library/rockylinux:9 bash
[root@f568df922041 /]#
创建后台运行的容器
[root@rocky ~]# docker run -itd --name rocky9 docker.io/library/rockylinux:9 bash
3.4 关闭、启动、重启容器
docker stop 容器名
[root@rocky ~]# docker stop rocky9
[root@rocky ~]# docker start rocky9
[root@rocky ~]# docker restart rocky9
3.5 进入容器
docker exec -it 容器名 bash
[root@rocky ~]# docker exec -it rocky9 bash
Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.
[root@b937013685ae /]#
# 不建议这种方式进入容器!!!
[root@rocky ~]# podman attach rocky9
3.6 删除容器
删除容器之前必须要停止容器,不然会报错
[root@rocky ~]# docker stop rocky9
[root@rocky ~]# docker rm rocky9
[root@rocky ~]# docker rm rocky8
3.7 始终运行容器
增加一个选项--restart=always
[root@rocky ~]# docker run -itd --restart=always --name rocky9 docker.io/library/rockylinux:9 bash
6b4448bcf070fdf3ccd5f1e5507b9a167ce3f08fd91c8a73f67a024e8930a04a
3.8 强制删除正在运行容器
docker rm -f 容器名/容器ID
[root@rocky ~]# docker rm -f 6b4448bcf070
Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.
6b4448bcf070
3.9 创建临时容器
临时容器:退出容器后自动删除
[root@rocky ~]# docker run -it --rm --name rocky9 docker.io/library/rockylinux:9 bash
[root@577ec59fe199 /]# exit
exit
[root@rocky ~]# docker ps -a
Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3.10 指定容器运行命令
docker run -it --name XX 容器名 [命令]
[root@rocky ~]# docker run -it --rm --name rocky9 docker.io/library/rockylinux:9 sleep 3
Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.
3.11 创建容器使用变量
加入-e参数指定变量
[root@rocky ~]# docker run -it -e var1=10 -e var2=20 --rm --name rocky9 docker.io/library/rockylinux:9 bash
[root@8b08438f1eaa /]# echo $var1
10
[root@8b08438f1eaa /]# echo $var2
20
3.12 容器端口映射
# 默认端口随机映射,指定端口映射
# 启动nginx
docker pull nginx
docker run -d --name web-nginx --restart always -p 80:80 nginx
# 类似启动httpd
docker pull httpd
docker run -d --name web-apache --restart always -p 80:80 httpd
3.13 创建Mysql容器
# 拉取mysql容器
docker pull mysql
# 初始化密码root,初始化数据库mmx
docker run -d --name mysql-db --restart=always -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=mmx mysql
# 安装Mariadb客户端
yum -y install mariadb
# 查看容器地址
docker inspect mysql-db | grep -i ipaddress
#=======================================#
Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.
"IPAddress": "10.88.0.26",
"IPAddress": "10.88.0.26",
#=======================================#
# 登陆mysql
[root@rocky ~]# mysql -uroot -proot -h10.88.0.26
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.33 MySQL Community Server - GPL
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MySQL [(none)]>
MySQL [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mmx |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.003 sec)
3.14 主机文件复制到容器
# docker cp 文件路径 容器名:/容器路径
docker cp /etc/hosts mysql-db:/opt
# 测试
[root@rocky ~]# docker cp /etc/hosts mysql-db:/opt/
[root@rocky ~]# docker exec mysql-db ls /opt/
hosts
3.15 容器文件复制到主机
# docker cp 容器名:/容器路径 文件路径
docker cp mysql-db:/opt/hosts hosts
# 测试
[root@rocky ~]# docker cp mysql-db:/opt/hosts hosts
Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.
[root@rocky ~]# ls
anaconda-ks.cfg hosts rocky9.tar
3.16 查看容器属性
docker inspect 容器名
[root@rocky ~]# docker inspect mysql-db
4、数据卷
4.1 数据卷使用
持久化保存容器数据
[root@rocky ~]# ls
anaconda-ks.cfg hosts rocky9.tar
[root@rocky ~]# mkdir data
[root@rocky ~]# mv rocky9.tar data/
[root@rocky ~]# docker run -itd --name rocky --restart=always -v data rockylinux:9
b06278f30ba62a18c2e3db191f1735ca480f35c4ab96ea8d3f195ff94a468fce
# 复制一份数据到/root/data
[root@rocky ~]# docker cp /etc/hosts rocky:/root/data
# 验证配置文件
[root@rocky ~]# podman inspect rocky | grep -i mount -A 5
...
"Source": "/var/lib/containers/storage/volumes/4c797404ac05854373949a7119bee85bf370652a49b0bcda7b7eac356c9b50ad/_data",
"Destination": "/root/data/",
# 在主机中可以找到
[root@rocky data]# cd /var/lib/containers/storage/volumes/4c797404ac05854373949a7119bee85bf370652a49b0bcda7b7eac356c9b50ad/_data/
[root@rocky _data]# ls
hosts
[root@rocky _data]# cat hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
...
# 验证挂载
[root@rocky ~]# docker exec rocky ls ~/data/
[root@rocky ~]# docker exec rocky bash
[root@rocky ~]# ls
anaconda-ks.cfg data hosts
[root@rocky ~]# cd data/
[root@rocky data]# ls
rocky9.tar
4.2 指定目录挂载数据卷
[root@rocky ~]# docker run -itd --name rocky2 --restart=always -v ./data:/root/data:rw rockylinux:9
# 验证
[root@rocky ~]# podman inspect rocky2 | grep -i mount -A 5
"MountLabel": "system_u:object_r:container_file_t:s0:c788,c826",
"ProcessLabel": "system_u:system_r:container_t:s0:c788,c826",
"AppArmorProfile": "",
"EffectiveCaps": [
"CAP_CHOWN",
"CAP_DAC_OVERRIDE",
--
"Mounts": [
{
"Type": "bind",
"Source": "/root/data",
"Destination": "/root/data",
"Driver": "",
# 拷贝文件进入目录
[root@rocky ~]# docker cp /etc/hosts rocky:/root/data
# 查看目录
[root@rocky ~]# ls data/
hello.txt hosts rocky9.tar
4.3 卷挂载权限问题
权限 | 表示 |
读写 | rw |
只读 | ro |
# 可读写
docker run -itd --name rocky2 --restart=always -v ./data:/root/data:rw rockylinux:9
# 只读
docker run -itd --name rocky2 --restart=always -v ./data:/root/data:ro rockylinux:9
4.4 卷挂载无法访问问题
# 注意,SELinux未关闭的情况下,需要手动指定SELinux,此时就能正确查看目录
[root@rocky ~]# chcon -t container_file_t data/
[root@rocky ~]# ls -ldZ data/
drw-r--r--. 2 root root unconfined_u:object_r:container_file_t:s0 54 6月 1 01:18 data/
[root@rocky ~]# docker exec rocky2 ls /root/data
hello.txt
hosts
rocky9.tar
# 临时指定 SELinux 上下文
chcon -R -t <TYPE>:<ROLE>:<USER> /path/to/directory
# 永久指定 SELinux 上下文
semanage fcontext -a -t <TYPE>:<ROLE>:<USER> /path/to/directory
restorecon -R /path/to/directory
5、 docker网络
5.1 查看默认网络
[root@rocky ~]# podman network ls
NETWORK ID NAME DRIVER
2f259bab93aa podman bridge
5.2 查看默认网络详细信息
[root@rocky ~]# podman network inspect 2f259bab93aa
[
{
"name": "podman",
"id": "2f259bab93aaaaa2542ba43ef33eb990d0999ee1b9924b557b7be53c0b7a1bb9",
"driver": "bridge",
"network_interface": "podman0",
"created": "2023-06-01T01:40:09.916525151+08:00",
"subnets": [
{
"subnet": "10.88.0.0/16",
"gateway": "10.88.0.1"
}
],
"ipv6_enabled": false,
"internal": false,
"dns_enabled": false,
"ipam_options": {
"driver": "host-local"
}
}
]
5.3 创建新的docker网络
[root@rocky ~]# podman network create -d bridge --subnet 10.0.0.0/24 mynet
mynet
# 验证
[root@rocky ~]# podman network ls
NETWORK ID NAME DRIVER
190cafd3b01c mynet bridge
2f259bab93aa podman bridge
[root@rocky ~]# podman network inspect 190cafd3b01c
[
{
"name": "mynet",
"id": "190cafd3b01c4db9105ffabed3def2b4141bcc77ff746fabc7793dd713df9378",
"driver": "bridge",
"network_interface": "podman1",
"created": "2023-06-01T01:41:28.750774771+08:00",
"subnets": [
{
"subnet": "10.0.0.0/24",
"gateway": "10.0.0.1"
}
],
"ipv6_enabled": false,
"internal": false,
"dns_enabled": true,
"ipam_options": {
"driver": "host-local"
}
}
]
5.4 删除docker网络
[root@rocky ~]# podman network rm mynet
mynet
5.5 创建新容器连接到新建网络
# 创建网络
[root@rocky ~]# podman network create -d bridge --subnet 10.0.0.0/24 mynet
mynet
# 创建容器,使用mynet网络
[root@rocky ~]# docker run --net=mynet -it --name rocky-mynet --restart=always rockylinux:9
# 验证是否已经是10.0.0.0/24网段网络
[root@rocky ~]# podman inspect rocky-mynet | grep -i ipaddress
"IPAddress": "",
"IPAddress": "10.0.0.2",
6、容器互联
WordPress是使用PHP语言开发的博客平台,可以通过与Mysql数据库建立连接搭建自己的博客平台
6.1 查看Mysql数据网络地址
# 查看Mysql数据网络地址
[root@rocky ~]# podman inspect mysql-db | grep -i ipaddress
"IPAddress": "10.88.0.26",
"IPAddress": "10.88.0.26",
6.2 拉取WordPress镜像
# 拉取WordPress镜像
docker pull wordpress
6.3 创建容器
# 创建WordPress容器,公开其端口以接受服务请求
docker run -itd --name blog --restart=always \
-e WORDPRESS_DB_HOST=10.88.0.26 \
-e WORDPRESS_DB_USER=root \
-e WORDPRESS_DB_PASSWORD=root \
-e WORDPRESS_DB_NAME=mmx \
-p 80:80 wordpress
6.4 预览图
7、自定义镜像
- 常用的数据库、中间件、应用软件都有现成的Docker官方镜像或其他人或组织或第三方创建的镜像
- Docker提供了两种创建新镜像的方式:docker commit和Dockerfile
- Dockerfile是镜像的描述文件,定义了如何构建Docker镜像。Dockerfile语法简洁,可读性强(FROM、RUN、CMD)
7.1 编写Dockerfile
安装net-tools软件包
FROM rockylinux:9
RUN yum -y install net-tools
CMD ['/bin/sh']
7.2 构建新镜像
基于rockylinux:9构建新的镜像,-t参数是新镜像名字和tag
docker build -t rocky9:new . -f Dockerfile
7.3 查看镜像
[root@rocky rocky9]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/rocky9 new 54b16d163fe1 11 seconds ago 224 MB
7.4 拉起容器测试
docker run -it --rm rocky9:new bash
[root@rocky rocky9]# docker run -it --rm rocky9:new bash
[root@7641899af624 /]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.88.0.11 netmask 255.255.0.0 broadcast 10.88.255.255
inet6 fe80::2c98:92ff:fed6:32e1 prefixlen 64 scopeid 0x20<link>
ether 2e:98:92:d6:32:e1 txqueuelen 1000 (Ethernet)
RX packets 13 bytes 1649 (1.6 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 6 bytes 516 (516.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
8、私有仓库搭建
容器、镜像和镜像仓库的关系
8.1 拉取registry镜像
docker pull registry:latest
8.2 创建仓库目录并设置SELinux
mkdir /registry
semanage fcontext -a -t container_file_t /registry
restorecon -RvF /registry
# 测试
[root@rocky ~]# ls -ldZ /registry
drwxr-xr-x. 2 root root system_u:object_r:container_file_t:s0 6 6月 1 21:22 /registry
8.3 创建registry容器
registry容器默认使用5000端口,并将上传的容器保存在/var/lib/registry目录中
docker run -d --name registry -v /registry:/var/lib/registry -p 5000:5000 --restart=always registry:latest
8.4 修改私有仓库tag
docker tag registry:latest 192.168.0.129:5000/registry:latest
docker tag httpd:latest 192.168.0.129:5000/httpd
8.5 修改配置文件
[root@rocky ~]# grep -Ev '$^|^#' /etc/containers/registries.conf
unqualified-search-registries = ["docker.io"]
insecure-registry = ['192.168.0.129:5000']
short-name-mode = "enforcing"
8.6 放行防火墙
[root@rocky ~]# firewall-cmd --add-port=5000/tcp --permanent
success
[root@rocky ~]# firewall-cmd --reload
success
8.6 配置Https认证
#!/bin/bash
HOST_IP=192.168.0.129
mkdir -p /registry/{auth,certs,data}
# 用户名mmx,密码mmx123
htpasswd -bBc /registry/auth/htpasswd mmx mmx123
cat << EOF > ssl.conf
[ req ]
prompt = no
distinguished_name = req_subj
x509_extensions = x509_ext
[ req_subj ]
CN = Localhost
[ x509_ext ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
basicConstraints = CA:true
subjectAltName = @alternate_names
[ alternate_names ]
DNS.1 = localhost
IP.1 = $HOST_IP
EOF
# 配置x509认证,生成证书
openssl req -config ssl.conf -new -x509 -nodes -sha256 -days 365 -newkey rsa:4096 -keyout /registry/certs/domain.key -out /registry/certs/domain.crt
openssl x509 -inform PEM -in /registry/certs/domain.crt -out /registry/certs/domain.cert
# 创建认证目录,将证书复制到目录中
mkdir -p /etc/containers/certs.d/$HOST_IP\:5000/
cp -r /registry/certs/* /etc/containers/certs.d/$HOST_IP\:5000/
cp /registry/certs/domain.crt /etc/pki/ca-trust/source/anchors/
update-ca-trust
8.7 创建registry容器
docker run --name myregistry \
-p 5000:5000 \
-v /registry/data:/var/lib/registry:z \
-v /registry/auth:/auth:z \
-e "REGISTRY_AUTH=htpasswd" \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
-v /registry/certs:/certs:z \
-e "REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt" \
-e "REGISTRY_HTTP_TLS_KEY=/certs/domain.key" \
-e REGISTRY_COMPATIBILITY_SCHEMA1_ENABLED=true \
-e REGISTRY_STORAGE_DELETE_ENABLED=true \
-d docker.io/library/registry:latest
8.8 登陆镜像仓库
[root@rocky auth]# docker login -u mmx -p mmx123 192.168.0.129:5000
Login Succeeded!
8.9 上传镜像
[root@rocky auth]# docker push 192.168.0.129:5000/registry
Getting image source signatures
Copying blob f8dc4f9c98a6 done
Copying blob 4984fbd72df1 done
Copying blob 744dbed40ffa done
Copying blob bb01bd7e32b5 done
Copying blob 6e5160500bc7 done
Copying config 65f3b3441f done
Writing manifest to image destination
Storing signatures
8.10 测试
# 上传镜像
docker pull 192.168.0.129:5000/registry
docker push 192.168.0.129:5000/httpd
# 查看镜像仓库镜像
[root@rocky ~]# podman search 192.168.0.129:5000/
NAME DESCRIPTION
192.168.0.129:5000/httpd
192.168.0.129:5000/registry
# 删除旧的镜像
[root@rocky data]# docker rmi 192.168.0.129:5000/registry
Untagged: 192.168.0.129:5000/registry:latest
[root@rocky ~]# docker rmi docker.io/library/httpd
# 查看镜像
[root@rocky ~]# docker search 192.168.0.129:5000/
NAME DESCRIPTION
192.168.0.129:5000/httpd
192.168.0.129:5000/registry
# 从仓库拉取镜像
[root@rocky ~]# docker pull 192.168.0.129:5000/httpd
Trying to pull 192.168.0.129:5000/httpd:latest...
Getting image source signatures
Copying blob dea060b46dfa skipped: already exists
Copying blob 4f81d279c536 done
Copying blob 7adebb4211f2 done
Copying blob 30759271a46d done
Copying blob 3690927ccba7 done
Copying config d1676199e6 done
Writing manifest to image destination
Storing signatures
d1676199e60591c70e38ddfde2c6c3fc51452fafeeeab485f6713d715dacee3a
[root@rocky ~]# docker pull 192.168.0.129:5000/registry
Trying to pull 192.168.0.129:5000/registry:latest...
Getting image source signatures
Copying blob 0b76a76affcd skipped: already exists
Copying blob 4fec85a294fa skipped: already exists
Copying blob 18084e71cbfa skipped: already exists
Copying blob ceedeadd4847 skipped: already exists
Copying blob acdaa0f0acc4 skipped: already exists
Copying config 65f3b3441f done
Writing manifest to image destination
Storing signatures
65f3b3441f044d142ca365389fe0532900b4f4c7ffc47cb65f7bc7bd45857f06