dockerBIE
Docker 容器本质上是宿主机上的一个进程。Docker 通过 namespace 实现了资源隔离,通过 cgroups 实现了资源的限制,通过写时复制机制(copy-on-write)实现了高效的文件操作。
Docker有五个命名空间:进程、网络、挂载、宿主和共享内存,为了隔离有问题的应用,Docker运用Namespace将进程隔离,为进程或进程组创建已隔离的运行空间,为进程提供不同的命名空间视图。这样,每一个隔离出来的进程组,对外就表现为一个container(容器)。需要注意的是,Docker让用户误以为自己占据了全部资源,但这并不是”虚拟机”。
image
概念
Docker 中的三个概念:镜像,容器,仓库
镜像(image):
Docker 镜像就是一个只读的模板,镜像可以用来创建 Docker 容器。Docker 提供了一个很简单的机制来创建镜像或者更新现有的镜像,用户甚至可以直接从其他人那里下载一个已经做好的镜像来直接使用。镜像是一种文件结构。Dockerfile中的每条命令都会在文件系统中创建一个新的层次结构,文件系统在这些层次上构建起来,镜像就构建于这些联合的文件系统之上。Docker官方网站专门有一个页面来存储所有可用的镜像,网址是:index.docker.io。
例如:一个镜像可以包含一个完整的CentOS操作系统环境,里面仅安装了Nginx或用户需要的其他应用程序。镜像可以用来创建Docker容器。
容器( Container):
容器是从镜像创建的运行实例。它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。可以把容器看做是一个简易版的 Linux 环境,Docker 利用容器来运行应用。镜像是只读的,容器在启动的时候创建一层可写层作为最上层。
注意:镜像是只读的,容器在启动的时候创建一层可写层作为最上层。
仓库:
仓库是集中存放镜像文件的场所,有时候把仓库和仓库注册服务器(Registry)混为一谈,并不严格区分。仓库注册服务器(Registry)上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(tag)。目前,最大的公开仓库是 Docker Hub,存放了数量庞大的镜像供用户下载。
仓库分为公开仓库(Public)和私有仓库(Private)两种形式。
Docker仓库用来保存我们的images,当我们创建了自己的image之后我们就可以使用push命令将它上传到公有或者私有仓库,这样下次要在另外一台机器上使用这个image时候,只需要从仓库上pull下来就可以了。
注意:Docker 仓库的概念跟 Git 类似,注册服务器可以理解为 GitHub 这样的托管服务。
一、基础环境
基础配置
NAT
192.168.0.10 K8s-master
192.168.0.20 K8s-node01
192.168.0.30 K8s-node02
LAN
172.16.0.10 K8s-master
172.16.0.20 K8s-node01
172.16.0.30 K8s-node02
基础优化配置三台环境
echo 'net.ipv4.ip_forward=1 ' >>/etc/sysctl.conf
echo 'net.ipv4.tcp_tw_recycle=1 ' >>/etc/sysctl.conf
echo 'net.ipv4.tcp_tw_reuse=1 ' >>/etc/sysctl.conf
sysctl -p
chmod +x /etc/rc.d/rc.local
yum install -y mlocate lrzsz tree vim nc nmap wget bash-completion bash-completion-extras htop iotop iftop lsof net-tools sysstat unzip bc psmisc ntpdate wc telnet-server bind-utils sshpass
配置yum源
curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
在master节点上分发ssh秘钥
[root@K8s-master ~]# cat fenfa_pub.sh
#!/bin/bash
ssh-keygen -t rsa -f ~/.ssh/id_rsa -P ''
for ip in 20 30
do
sshpass -p123456 ssh-copy-id -o StrictHostKeyChecking=no 172.16.0.$ip
done
sh fenfa_pub.sh
在master节点上为其他node节点分发hosts文件
[root@k8s-master ~]# cat /etc/hosts
172.16.0.10 k8s-master
172.16.0.20 k8s-node01
172.16.0.30 K8s-node02
for ip in 20 30 ;do scp -rp /etc/hosts 172.16.0.$ip:/etc/hosts ;done
二、最新版19.03安装
https://docs.docker.com/engine/install/centos/
注意:确保自己的linux系统内核版本高于3.10,并且系统是64位,才能体验Docker。
[root@k8s-master ~]# uname -r
3.10.0-957.el7.x86_64
官方帮助文档:
较旧的Docker版本称为docker
或docker-engine
。如果已安装这些程序,请卸载它们以及相关的依赖项。
# 1. 卸载旧版本
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
# 2. 使用存储库安装
yum install -y yum-utils
# 3. 设置镜像仓库(修改为国内源地址)
yum-config-manager \
--add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 5. 更新索引
yum makecache fast
# 4. 安装docker相关的依赖 默认最新版(docker-ce:社区版 ee:企业版)
yum install docker-ce docker-ce-cli containerd.io -y
#5. 安装特定docker版本(先列出列出可用版本)
yum list docker-ce --showduplicates | sort -r
yum install docker-ce-19.03.9 docker-ce-cli-19.03.9 containerd.io
# 6. 启动docker
systemctl start docker
systemctl enable docker
# 7. 查看版本
[root@k8s-master ~]# docker --version
Docker version 19.03.11, build 42e35e61f3
image
配置docker镜像加速器
镜像加速器:阿里云加速器,daocloud加速器,中科大加速器
Docker 中国官方镜像加速:https://registry.docker-cn.com
mkdir -p /etc/docker
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://registry.docker-cn.com"]
}
EOF
systemctl daemon-reload
systemctl restart docker
卸载docker
# 1. 卸载依赖
yum remove docker-ce docker-ce-cli containerd.io
# 2. 删除资源(默认工作路径)
rm -rf /var/lib/docker
ansible命令部署多台docker环境(需要配置ssh免秘钥)
# 1. 安装ansible
yum install ansible -y
# 2. 添加hosts文件列表(所有节点的IP地址)
[root@k8s-master ~]# vim /etc/ansible/hosts
...
[master]
172.16.0.10
[node]
172.16.0.20
172.16.0.30
# 3. 测试连通性
[root@k8s-master ~]# ansible all -a 'hostname'
172.16.0.20 | CHANGED | rc=0 >>
k8s-node01
172.16.0.30 | CHANGED | rc=0 >>
k8s-node02
172.16.0.10 | CHANGED | rc=0 >>
k8s-master
# 3.卸载旧版本(没有写playbook文件)
ansible all -m yum -a 'name=docker,docker-client,docker-client-latest.docker-common,docker-latest,docker-latest-logrotate,docker-logrotate,docker-engine state=absent'
# 4. 安装yum-utils
ansible all -m yum -a 'name=yum-utils state=installed'
# 5. 设置国内镜像仓库
ansible all -m shell -a 'yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo'
# 6. 更新yum
ansible all -m shell -a 'yum makecache fast'
# 7. 安装docker相关的依赖
ansible all -m yum -a 'name=docker-ce,docker-ce-cli,containerd.io state=installed'
# 8. 启动docker
ansible all -m service -a 'name=docker state=started enabled=yes'
三、Docker常用命令
帮助命令
docker version #显示docker版本信息
docker info #显示docker系统信息,包括镜像和容器的数量
docker --help #帮助
镜像命令
https://docs.docker.com/engine/reference/commandline/images/
[root@openvpn ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
kylemanna/openvpn 2.4 c504c01ae011 2 years ago 15.6MB
#解释
REPOSITORY 镜像的仓库源
TAG 镜像的标签
IMAGE ID 镜像的id
CREATED 镜像的创建时间
SIZE 镜像的大小
#可选参数
-a --all #列出所有镜像
-q --quiet #只显示镜像ID
搜索镜像命令
https://docs.docker.com/engine/reference/commandline/search/
[root@k8s-master ~]# docker search mysql --filter=stars=5000
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 9636 [OK]
#可选参数
--filter=stars=5000 #显示至少x个星标的
下载镜像命令
https://docs.docker.com/engine/reference/commandline/pull/
#下载镜像 docker pull [镜像名:tag]
[root@k8s-master ~]# docker pull mysql
Using default tag: latest #如果不写tag,默认下载latest
latest: Pulling from library/mysql
8559a31e96f4: Pull complete #分层下载,docker image的核心 联合文件系统
d51ce1c2e575: Pull complete
c2344adc4858: Pull complete
fcf3ceff18fc: Pull complete
16da0c38dc5b: Pull complete
b905d1797e97: Pull complete
4b50d1c6b05c: Pull complete
c75914a65ca2: Pull complete
1ae8042bdd09: Pull complete
453ac13c00a3: Pull complete
9e680cd72f08: Pull complete
a6b5dc864b6c: Pull complete
Digest: sha256:8b7b328a7ff6de46ef96bcf83af048cb00a1c86282bfca0cb119c84568b4caf6
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest #真实地址
#等同的命令
docker pull mysql
docker pull docker.io/library/mysql:latest
#通过tag下载
[root@k8s-master ~]# docker pull mysql:5.7
5.7: Pulling from library/mysql
8559a31e96f4: Already exists #已下载的分层跳过,直接下载修改的内容
d51ce1c2e575: Already exists
c2344adc4858: Already exists
fcf3ceff18fc: Already exists
16da0c38dc5b: Already exists
b905d1797e97: Already exists
4b50d1c6b05c: Already exists
d85174a87144: Pull complete
a4ad33703fa8: Pull complete
f7a5433ce20d: Pull complete
3dcd2a278b4a: Pull complete
Digest: sha256:32f9d9a069f7a735e28fd44ea944d53c61f990ba71460c5c183e610854ca4854
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7
删除镜像命令
#删除镜像
docker rmi -f [镜像id] [镜像id]
-f 强制删除图像
#删除所有镜像
docker rmi `docker images -qa`
导出镜像
# 导出镜像
docker image save centos -o docker-centos7.6.tar.gz
导入镜像
# 导入镜像
docker load -i docker-centos7.6.tar.gz
容器命令
说明:有了镜像才可以创建容器,在linux里 下载一个centos的镜像来测试
[root@k8s-master ~]# docker pull centos
新建容器并启动
docker run [参数] image
#参数说明
--name='Name' 区分容器
-d 后台方式运行
-it 使用交互方式运行,进入容器查看内容
-p [小写] 指定容器的端口 -p 8080:8080
-p ip:主机端口:容器端口
-p 主机端口:容器端口
-p 容器端口
-P [大写] 随机指定端口
-rm 容器退出后随之将其删除
#启动并进入容器
[root@k8s-master ~]# docker run -it centos:latest /bin/bash
[root@f17bd1e56cbf /]# ls
bin etc lib lost+found mnt proc run srv tmp var
dev home lib64 media opt root sbin sys usr
#从容器中退回主机
[root@f17bd1e56cbf /]# exit
exit
[root@k8s-master ~]#
容器资源限制的参数
image
列出所有的运行的容器
#docker ps 命令
-a #列出当前所有的容器
-q #显示容器的编号
-n=1 #显示最近创建的容器
[root@k8s-master /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@k8s-master /]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f17bd1e56cbf centos:latest "/bin/bash" 6 minutes ago Exited (0) 3 minutes ago exciting_benz
退出容器
exit #直接容器停止并退出
ctrl +P +Q #容器不停止退出
[root@8df0a450ef49 /]# #输入ctrl+PQ
[root@8df0a450ef49 /]# read escape sequence
[root@k8s-master /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8df0a450ef49 centos "/bin/bash" 48 seconds ago Up 48 seconds elegant_nash
删除容器
docker rm 容器id #删除指定的容器,不能正在删除正在运行的容器
docker rm -f $(docker ps -aq) #删除所有容器
docker ps -aq|xargs docker rm #删除所有容器
启动和停止容器的操作
docker start #启动容器
docker restart #重启容器
docker stop #关闭当前运行的容器
docker kill #强制关闭当前容器
docker stats #容器占用内存状态
常用其他命令
后台启动容器
#问题!
#命令 docker run -d [镜像名] 启动容器失败
[root@k8s-master /]# docker run -d centos
045d6e51f4ebf39aec13bfe19172ceb34081bd69921108f684cfc879bc58ab29
#docker ps 会发现centos停止了
[root@k8s-master /]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
045d6e51f4eb centos "/bin/bash" 7 seconds ago Exited (0) 6 seconds ago optimistic_benz
#常见的坑,docker 容器使用后台运行,就必须要有一个前台进程,docker发现没有应用,就会自动停止
查看日志
https://docs.docker.com/engine/reference/commandline/logs/
#运行一个容器,会发现没有日志
docker logs -f -t --tail 10 [容器id]
-f #跟踪日志输出
-t #显示时间戳
--tail #从日志末尾开始显示的行数
#编写一个shell脚本运行容器
"while true;do echo 666666;sleep 1;done"
[root@k8s-master /]# docker run -d centos /bin/sh -c "while true;do echo 666666;sleep 1;done"
d297ff12a815e8c1dd86ad951c30caca389ec5e854b6948c8b93d0e26ed7e10e
[root@k8s-master /]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d297ff12a815 centos "/bin/sh -c 'while t…" 2 seconds ago Up 1 second angry_ardinghelli
#显示日志
[root@k8s-master /]# docker logs -f -t --tail 5 d297ff12a815
2020-06-18T09:38:26.352615139Z 666666
2020-06-18T09:38:27.357596179Z 666666
2020-06-18T09:38:28.363849798Z 666666
2020-06-18T09:38:29.369256113Z 666666
2020-06-18T09:38:30.377091746Z 666666
查看容器中进程信息
# docker top [容器id]
[root@k8s-master /]# docker top 480d8e4936dc
UID PID PPID C STIME TTY TIME CMD
root 12812 12794 0 17:42 pts/0 00:00:00 /bin/bash
查看容器元数据
# docker inspect [容器id]
[root@k8s-master /]# docker inspect d297ff12a815
[
{
"Id": "d297ff12a815e8c1dd86ad951c30caca389ec5e854b6948c8b93d0e26ed7e10e",
"Created": "2020-06-18T09:37:38.560647732Z",
"Path": "/bin/sh",
"Args": [
"-c",
"while true;do echo 666666;sleep 1;done"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 12246,
"ExitCode": 0,
"Error": "",
"StartedAt": "2020-06-18T09:37:39.066548855Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:831691599b88ad6cc2a4abbd0e89661a121aff14cfa289ad840fd3946f274f1f",
"ResolvConfPath": "/var/lib/docker/containers/d297ff12a815e8c1dd86ad951c30caca389ec5e854b6948c8b93d0e26ed7e10e/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/d297ff12a815e8c1dd86ad951c30caca389ec5e854b6948c8b93d0e26ed7e10e/hostname",
"HostsPath": "/var/lib/docker/containers/d297ff12a815e8c1dd86ad951c30caca389ec5e854b6948c8b93d0e26ed7e10e/hosts",
"LogPath": "/var/lib/docker/containers/d297ff12a815e8c1dd86ad951c30caca389ec5e854b6948c8b93d0e26ed7e10e/d297ff12a815e8c1dd86ad951c30caca389ec5e854b6948c8b93d0e26ed7e10e-json.log",
"Name": "/angry_ardinghelli",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": null,
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "default",
"PortBindings": {},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"CapAdd": null,
"CapDrop": null,
"Capabilities": null,
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "private",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"ConsoleSize": [
0,
0
],
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": [],
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": null,
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DeviceCgroupRules": null,
"DeviceRequests": null,
"KernelMemory": 0,
"KernelMemoryTCP": 0,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": null,
"OomKillDisable": false,
"PidsLimit": null,
"Ulimits": null,
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": [
"/proc/asound",
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware"
],
"ReadonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
},
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/262154243dfb5fcc88ee7ebc33f14eb633ab80762c3c590ae6dd47963fa9c258-init/diff:/var/lib/docker/overlay2/c136121eb67e6c71677589843a6b4a68655638d12f4c79ce634d224b7239228e/diff",
"MergedDir": "/var/lib/docker/overlay2/262154243dfb5fcc88ee7ebc33f14eb633ab80762c3c590ae6dd47963fa9c258/merged",
"UpperDir": "/var/lib/docker/overlay2/262154243dfb5fcc88ee7ebc33f14eb633ab80762c3c590ae6dd47963fa9c258/diff",
"WorkDir": "/var/lib/docker/overlay2/262154243dfb5fcc88ee7ebc33f14eb633ab80762c3c590ae6dd47963fa9c258/work"
},
"Name": "overlay2"
},
"Mounts": [],
"Config": {
"Hostname": "d297ff12a815",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh",
"-c",
"while true;do echo 666666;sleep 1;done"
],
"Image": "centos",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {
"org.label-schema.build-date": "20200611",
"org.label-schema.license": "GPLv2",
"org.label-schema.name": "CentOS Base Image",
"org.label-schema.schema-version": "1.0",
"org.label-schema.vendor": "CentOS"
}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "536bd691e3316eca9f9ad9902a9cfa7b0b37df0a384dc617a87453355a17fea0",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {},
"SandboxKey": "/var/run/docker/netns/536bd691e331",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "4e4b82daee88df3a954ce8b905ba24c894858668d28211d47e0617641911c6ae",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:02",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "35ca8cfcee1b97f050ae2e99c9f0c46b94009313ecb938325043f8d685cb93ba",
"EndpointID": "4e4b82daee88df3a954ce8b905ba24c894858668d28211d47e0617641911c6ae",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02",
"DriverOpts": null
}
}
}
}
]
进入当前正在运行的容器
# 通常容器都是使用后台方式运行的,需要进入容器,修改一些配置
#方式一
#打开了新的终端,可以在里操作
docker exec -it [容器id] /bin/bash
[root@k8s-master /]# docker exec -it f1b799deb1b5 /bin/bash
[root@f1b799deb1b5 /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
[root@f1b799deb1b5 /]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 09:56 pts/0 00:00:00 /bin/bash
root 14 0 0 09:57 pts/1 00:00:00 /bin/bash
root 28 1 0 09:57 pts/0 00:00:00 ps -ef
#方式二
#进入容器当前正在执行的终端
docker attach [容器id]
[root@k8s-master ~]# docker attach f1b799deb1b5
[root@f1b799deb1b5 /]#
从容器内拷贝文件到主机
docker cp 容器id:容器内id 目的主机路径
#进入容器创建一个文件
[root@k8s-master ~]# docker attach f1b799deb1b5
[root@f1b799deb1b5 /]# echo {a..z} >test.txt
[root@f1b799deb1b5 /]# cat /test.txt
a b c d e f g h i j k l m n o p q r s t u v w x y z
#将容器的文件拷贝到主机上
[root@k8s-master ~]# docker cp f1b799deb1b5:/test.txt /tmp/
[root@k8s-master ~]# ls /tmp/test.txt
/tmp/test.txt
[root@k8s-master ~]# cat /tmp/test.txt
a b c d e f g h i j k l m n o p q r s t u v w x y z
#拷贝是一个手动过程,之后使用 -v 卷的技术,可以实现自动同步;主机目录和容器目录同步
查看镜像、容器、数据卷所占用的空间
# docker system df
[root@k8s-master ~]# docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 1 1 215.3MB 0B (0%)
Containers 1 0 104B 104B (100%)
Local Volumes 2 0 0B 0B
Build Cache 0 0 0B 0B
四、测试docker镜像运行各种环境
1. 测试运行一个nginx容器,端口映射到主机的3344
[root@k8s-master ~]# docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
8559a31e96f4: Pull complete
8d69e59170f7: Pull complete
3f9f1ec1d262: Pull complete
d1f5ff4f210d: Pull complete
1e22bfa8652e: Pull complete
Digest: sha256:21f32f6c08406306d822a0e6e8b7dc81f53f336570e852e25fbe1e3e3d0d0133
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest
[root@k8s-master ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos latest 831691599b88 2 days ago 215MB
nginx latest 2622e6cca7eb 9 days ago 132MB
[root@k8s-master ~]# docker run -d --name nginx01 -p 3344:80 nginx:latest
145afc9f6eaa994b51d2c00bb28613bff2b1f9a48ea7f26a3c591bd40102cdd9
[root@k8s-master ~]# curl -I 127.0.0.1:3344
HTTP/1.1 200 OK
Server: nginx/1.19.0
Date: Fri, 19 Jun 2020 03:13:22 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 26 May 2020 15:00:20 GMT
Connection: keep-alive
ETag: "5ecd2f04-264"
Accept-Ranges: bytes
# 进入容器
[root@k8s-master ~]# docker exec -it nginx01 /bin/bash
root@145afc9f6eaa:/# whereis nginx
nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx
root@145afc9f6eaa:/# cd /etc/nginx/
root@145afc9f6eaa:/etc/nginx# ls
conf.d koi-utf mime.types nginx.conf uwsgi_params
fastcgi_params koi-win modules scgi_params win-utf
image
2. 测试运行一个tomcat的容器,端口映射到主机的3355
https://hub.docker.com/_/tomcat
# 下载镜像再启动
docker pull tomcat
# 启动运行
docker run -d -p 3355:8080 --name tomcat01 tomcat
# 访问此容器会报错404,是因为tomcat官网镜像没有webapps,镜像源把所有镜像不必要的都剔除了,默认是最小可运行环境
# 进入容器,将默认的webapps.dist的内容拷贝一份到webapps目录下
[root@k8s-master ~]# docker exec -it tomcat01 /bin/bash
root@23e4e460879b:/usr/local/tomcat# cp -a webapps.dist/* webapps/
# 再一次访问就成功了
[root@k8s-master ~]# curl -I 127.0.0.1:3355
HTTP/1.1 200
Content-Type: text/html;charset=UTF-8
Transfer-Encoding: chunked
Date: Fri, 19 Jun 2020 03:39:34 GMT
image
每次改动服务配置文件,都需要进入容器内部,十分麻烦,我们可以在容器外映射一个路径,达到在宿主机修改文件内容,容器内部就可以自动同步修改,就是数据卷的操作
3. 测试部署一套elasticsearch+kibana的日志监控的容器
https://hub.docker.com/_/elasticsearch
启动一台es容器
# es暴露的端口很多
# es十分耗内存
# es数据一般需要放置到安全目录挂载
# 启动elasticsearch
[root@k8s-master ~]# docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2
#访问
[root@k8s-master ~]# curl 127.0.0.1:9200
{
"name" : "7426e97975a1",
"cluster_name" : "docker-cluster",
"cluster_uuid" : "aNGISnU9QZm3qQw9obQiPg",
"version" : {
"number" : "7.6.2",
"build_flavor" : "default",
"build_type" : "docker",
"build_hash" : "ef48eb35cf30adf4db14086e8aabd07ef6fb113f",
"build_date" : "2020-03-26T06:34:37.794943Z",
"build_snapshot" : false,
"lucene_version" : "8.4.0",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
使用命令dcker stats
查看es容器的内存占用情况太大
image
# 关闭刚刚启动的es容器,增加内存的限制,修改配置文件 -e 环境配置修改
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2
image
[root@k8s-master ~]# curl 127.0.0.1:9200
{
"name" : "66fdfb9147aa",
"cluster_name" : "docker-cluster",
"cluster_uuid" : "7vONQG4HSjKXdtpMmEzbIg",
"version" : {
"number" : "7.6.2",
"build_flavor" : "default",
"build_type" : "docker",
"build_hash" : "ef48eb35cf30adf4db14086e8aabd07ef6fb113f",
"build_date" : "2020-03-26T06:34:37.794943Z",
"build_snapshot" : false,
"lucene_version" : "8.4.0",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
启动一台kibana容器
# 运行一台kibana7.6.2的容器,并添加到elasticsearch容器的网络中,使用--link或者创建自定义网络
docker run -d --name kibana --link elasticsearch -p 5601:5601 kibana:7.6.2
# 访问查看;选择一个样本数据进行测试是否与es连接
五、Docker可视化面板
# Portainer
基于Go,是一个轻量级的图形化界面管理工具,可轻松管理Docker主机。
# Rancher
开源的企业级容器管理平台,Rancher提供了在生产环境中使用管理Docker和Kubernetes的全栈化容器部署与管理平台。(CICD)
# cAdvisor
Google开发的容器监控工具, 会显示当前容器的资源使用情况,包括 CPU、内存、网络、文件系统等,显示容器列表。
启动一台portainer容器(不常用)
[root@k8s-master ~]# docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
访问8088端口 http://192.168.0.10:8088
image
image
image
2.Rancher
Rancher
是一个开源的企业级容器管理平台。通过Rancher
,企业不必自己使用一系列的开源软件去从头搭建容器服务平台。Rancher
提供了在生产环境中使用管理Docker
和Kubernetes
的全栈化容器部署与管理平台。
docker run -d --restart=unless-stopped -p 80:80 -p 443:443 rancher/rancher:v2.0.0
docker logs -f rancher
3. cAdvisor
cAdvisor
是Google
开发的容器监控工具。
- 监控 Docker Host cAdvisor 会显示当前 host 的资源使用情况,包括 CPU、内存、网络、文件系统等。
- 监控容器 点击 Docker Containers 链接,显示容器列表。点击某个容器,比如 sysdig,进入该容器的监控页面。
以上就是 cAdvisor 的主要功能,总结起来主要两点:
- 展示 Host 和容器两个层次的监控数据。
- 展示历史变化数据。
由于cAdvisor
提供的操作界面略显简陋,而且需要在不同页面之间跳转,并且只能监控一个 host,这不免会让人质疑它的实用性。但 cAdvisor 的一个亮点是它可以将监控到的数据导出给第三方工具,由这些工具进一步加工处理。
我们可以把 cAdvisor 定位为一个监控数据收集器,收集和导出数据是它的强项,而非展示数据。 cAdvisor 支持很多第三方工具,其中就包括Prometheus
。
docker run --volume=/:/rootfs:ro --volume=/var/run:/var/run:rw --volume=/sys:/sys:ro --volume=/var/lib/docker/:/var/lib/docker:ro --volume=/dev/disk/:/dev/disk:ro --publish=8080:8080 --detach=true --name=cadvisor google/cadvisor:latest
image.png
六、Docker镜像讲解
1. Docker镜像加载原理
UnionFS(联合文件系统)
下载镜像时看到的一层层的就是这个!
UnionFS(联合文件系统)
是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。UnionFS是Docker镜像的基础,镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
2. Docker commit定制镜像
docker不建议再通过这种方式构建镜像;具体原因如下
手工创建,容易出错,效率低并且可重复性弱。
无法对镜像进行审计,存在安全隐患。
学习commit定制镜像的原因:
dockerfile构建镜像,底层也是docker commit一层一层构建新镜像的,学习的目的是更加深入地理解构建过程和镜像分层结构。
三个步骤
- 运行容器
- 修改容器
- 将容器保存为新的镜像
# 第一步: 启动运行一个官方镜像的tomcat容器
[root@k8s-master ~]# docker run -it -d -p 8080:8080 --name tomcat02 tomcat
[root@k8s-master ~]# docker exec -it tomcat02 /bin/bash
# 第二步: 修改内容,将默认的webapps.dist/下内容复制到webapps下
root@81fd44790b38:/usr/local/tomcat# cp -a webapps.dist/* webapps/
# 第三步: commit提交
--a #是指定修改的作者
--m #是记录本次修改的内容
[root@k8s-master ~]# docker commit -a "lichenxing" -m "cp -a webapps.dist/* webapps/" tomcat02 tomcat02:V1.0
sha256:405a3c097a00380667ab5e3d4ed30458e5483cbb3182640c9275b2f82bc15f5d
# 第四步: 查看提交的镜像
[root@k8s-master ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat02 V1.0 405a3c097a00 34 seconds ago 652MB
tomcat latest 2eb5a120304e 9 days ago 647MB
七、Dokcer数据卷
容器的持久化和同步操作!容器间也是可以数据共享的!
容器删除后,数据还在主机上保存。
1. 使用数据卷
# 方式一: 直接使用命令挂载 -v
docker run -it -v 主机目录:容器目录
[root@k8s-master ~]# docker run -it -v /home/ceshi/:/home centos /bin/bash
[root@06b7f2dc16ec /]# ls /home/
# 容器挂载的/home/ceshi目录自动生成
[root@k8s-master ~]# ll /home/
total 0
drwxr-xr-x. 2 root root 6 Jun 19 16:36 ceshi
# 查看容器的详细信息(Mounts部分)
[root@k8s-master ~]# docker inspect 06b7f2dc16ec
"Mounts": [
{
"Type": "bind",
"Source": "/home/ceshi", # 主机内的地址
"Destination": "/home", # docker容器内的地址
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
# 主机目录和容器目录都为空,在容器内添加文件
[root@06b7f2dc16ec /]# cd /home/
[root@06b7f2dc16ec home]# touch test.java
# 在主机上查看,已经同步过来了
[root@k8s-master ~]# ll /home/ceshi/
total 0
-rw-r--r--. 1 root root 0 Jun 19 16:43 test.java
# 在主机上追加文件内容
[root@k8s-master ~]# echo {a..z} > /home/ceshi/test.java
# 在容器内查看文件
[root@06b7f2dc16ec home]# cat test.java
a b c d e f g h i j k l m n o p q r s t u v w x y z
修改只需要在主机本地修改即可,容器可以自动同步。
补充:
使用 --mount 标记可以指定挂载一个本地主机的目录到容器中去,如果使用mount时,宿主机中没有这个文件会报错,而不是像-v,没有这个文件也会自动创建。
# 挂载一个主机目录作为数据卷:(-v 和 --mount的对比)
docker run -d -P --name web \
# -v /src/webapp:/opt/webapp \
--mount type=bind,source=/src/webapp,target=/opt/webapp \
training/webapp \
python app.py
上面的命令加载主机的 /src/webapp 目录到容器的 /opt/webapp目录。这个功能在进行测试的时候十分方便,比如用户可以放置一些程序到本地目录中,来查看容器是否正常工作。本地目录的路径必须是绝对路径,以前使用 -v 参数时如果本地目录不存在 Docker 会自动为你创建一个文件夹,现在使用 --mount 参数时如果本地目录不存在,Docker 会报错。
# Docker 挂载主机目录的默认权限是 读写,用户也可以通过增加readonly指定为只读。
docker run -d -P --name web \
# -v /src/webapp:/opt/webapp:ro \
--mount type=bind,source=/src/webapp,target=/opt/webapp,readonly \
training/webapp \
python app.py
# 挂载一个本地主机文件作为数据卷:--mount标记也可以从主机挂载单个文件到容器中
docker run -it \
# -v /root/.bash_history:/root/.bash_history \
--mount type=bind,source=/root/.bash_history,target=/root/.bash_history \
ubuntu:17.10 \
bash
# 这样就可以记录在容器输入过的命令了。
root@2affd44b4667:/# history
1 ls
2 history
2. 安装MySQL
https://hub.docker.com/_/mysql
# 下载mysql5.7的官方镜像
docker pull mysql:5.7
# 运行一台mysql容器 (需要设置mysql密码; 映射配置文件和数据文件;通过官方镜像仓库查看启动容器的命令)
[root@k8s-master ~]# docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
0d709657652353d906f710118144ea401c6ce539c825abd2aa019e889278944c
#查看主机映射目录
[root@k8s-master home]# ls
ceshi lcx mysql
[root@k8s-master home]# cd mysql/
[root@k8s-master mysql]# ls
conf data
[root@k8s-master mysql]# ls data/
auto.cnf client-cert.pem ibdata1 ibtmp1 private_key.pem server-key.pem
ca-key.pem client-key.pem ib_logfile0 mysql public_key.pem sys
ca.pem ib_buffer_pool ib_logfile1 performance_schema server-cert.pem
通过本地第三方工具 SQLyog登陆mysql容器
image
image
新建一个数据库 test
image
# 查看主机映射目录也已经同步了test库目录
[root@k8s-master mysql]# ls data/
auto.cnf client-key.pem ib_logfile1 private_key.pem sys
ca-key.pem ib_buffer_pool ibtmp1 public_key.pem test
ca.pem ibdata1 mysql server-cert.pem
client-cert.pem ib_logfile0 performance_schema server-key.pem
3. 容器数据持久化
# 将容器删除后,数据已经保留下来了
[root@k8s-master ~]# docker rm -f mysql01
mysql01
[root@k8s-master mysql]# ls data/
auto.cnf client-key.pem ib_logfile1 private_key.pem sys
ca-key.pem ib_buffer_pool ibtmp1 public_key.pem test
ca.pem ibdata1 mysql server-cert.pem
client-cert.pem ib_logfile0 performance_schema server-key.pem
4. 具名和匿名挂载
匿名挂载:没有名字
# 启动一个nginx容器, 选择随机端口和随机挂载路径(只写了容器内的路径,没有写容器外的路径)
[root@k8s-master ~]# docker run -d -P --name nginx01 -v /etc/nginx nginx:latest
# 查看所有卷的情况(都是匿名卷,没有名字)
[root@k8s-master ~]# docker volume ls
DRIVER VOLUME NAME
local 6350e9d05a6611859fd3de283d1ea41eb234fc8720ec2d7a415d343ebc4e8de4
local a1b15cc90674c1d69f2f77e3b35543886d4f7ac40975f3dffe200df64e8e9b64
local bd43717a0bbfebd513b69fafa7ec3824805136b9ed7afd57605bfd3fedfd5662
local e8c6ff6336476cd8bbd65bee93e18ce1c073ab7901631d55312421f40fbde38d
local f2ecc7f10858285cda52f3a87bcc5e845f0de90785c56235744c9380cb7872cf
具名挂载:拥有名字
# 再启动一个nginx容器
[root@k8s-master ~]# docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx:latest
c446916349eefb151bf29f8ab657458e16deee7a46d65a3afa72b75a0ea30612
# 查看所有卷的情况(有名字为juming-nginx的卷)
[root@k8s-master ~]# docker volume ls
DRIVER VOLUME NAME
local 6350e9d05a6611859fd3de283d1ea41eb234fc8720ec2d7a415d343ebc4e8de4
local a1b15cc90674c1d69f2f77e3b35543886d4f7ac40975f3dffe200df64e8e9b64
local bd43717a0bbfebd513b69fafa7ec3824805136b9ed7afd57605bfd3fedfd5662
local e8c6ff6336476cd8bbd65bee93e18ce1c073ab7901631d55312421f40fbde38d
local f2ecc7f10858285cda52f3a87bcc5e845f0de90785c56235744c9380cb7872cf
local juming-nginx
# 查看具名挂载卷的路径
[root@k8s-master ~]# docker volume inspect juming-nginx
[
{
"CreatedAt": "2020-06-19T17:52:09+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/juming-nginx/_data",
"Name": "juming-nginx",
"Options": null,
"Scope": "local"
}
]
所有的docker容器内的卷,没有指定目录的情况下都是在
/var/lib/docker/volumes/xxx/_data
下
image
通过具名挂载可以方便的找到我们的卷,大多数情况在使用的是具名挂载
# 如何确定是具名挂载还是匿名挂载,还是指定路径挂载?
-v 容器内路径 #匿名挂载
-v 卷名:容器内路径 #具名挂载
-v /宿主机路径:容器内路径 #指定路径挂载
扩展:
# 通过 -v 容器内路径:ro/rw 改变读写权限
ro readonly #只读
rw readwrite #可读可写
# 一旦设置了容器的读写权限,容器对我们挂载出来的内容就会有了权限了。
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:ro nginx:latest
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:rw nginx:latest
# ro 只要看到ro就说明此路径是只能通过宿主机来操作,容器内部是无法操作修改的!
5. Dockerfile的基础操作
dockerfile 就是用来构建docker镜像的构建文件! 命令脚本。
# 创建一个存放dockerfile文件的目录
mkdir -p /home/docker-test-volume
# 编写一个dockerfile,生成镜像(指令都为大写)
# 每行命令,就是镜像的一层!
[root@k8s-master docker-test-volume]# cat dockerfile1
FROM centos
VOLUME ["volume01","volume02"]
CMD echo "----end----"
CMD /bin/bash
# 生成dockerfile文件
[root@k8s-master docker-test-volume]# docker build -f dockerfile1 -t lichenxing/centos:1.0 ./
Sending build context to Docker daemon 2.048kB
Step 1/4 : FROM centos
---> 831691599b88
Step 2/4 : VOLUME ["volume01","volume02"]
---> Running in 9a58f0ee53e5
Removing intermediate container 9a58f0ee53e5
---> 494b993538b5
Step 3/4 : CMD echo "----end----"
---> Running in 380c5748e66a
Removing intermediate container 380c5748e66a
---> 6f77f010dee6
Step 4/4 : CMD /bin/bash
---> Running in 002cd526e782
Removing intermediate container 002cd526e782
---> 62fd78da2572
Successfully built 62fd78da2572
Successfully tagged lichenxing/centos:1.0
# 查看生成的镜像
[root@k8s-master docker-test-volume]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
lichenxing/centos 1.0 62fd78da2572 43 seconds ago 215MB
# 使用生成的镜像创建一台容器
[root@k8s-master docker-test-volume]# docker run -it lichenxing/centos:1.0 /bin/bash
[root@1af48762856e /]#
# 查看目录,可以看到在dockerfile中自动挂载的数据卷
[root@1af48762856e /]# ls -l
total 0
lrwxrwxrwx. 1 root root 7 May 11 2019 bin -> usr/bin
drwxr-xr-x. 5 root root 360 Jun 23 03:31 dev
drwxr-xr-x. 1 root root 66 Jun 23 03:31 etc
drwxr-xr-x. 2 root root 6 May 11 2019 home
lrwxrwxrwx. 1 root root 7 May 11 2019 lib -> usr/lib
lrwxrwxrwx. 1 root root 9 May 11 2019 lib64 -> usr/lib64
drwx------. 2 root root 6 Jun 11 02:35 lost+found
drwxr-xr-x. 2 root root 6 May 11 2019 media
drwxr-xr-x. 2 root root 6 May 11 2019 mnt
drwxr-xr-x. 2 root root 6 May 11 2019 opt
dr-xr-xr-x. 130 root root 0 Jun 23 03:31 proc
dr-xr-x---. 2 root root 162 Jun 11 02:35 root
drwxr-xr-x. 11 root root 163 Jun 11 02:35 run
lrwxrwxrwx. 1 root root 8 May 11 2019 sbin -> usr/sbin
drwxr-xr-x. 2 root root 6 May 11 2019 srv
dr-xr-xr-x. 13 root root 0 Jun 23 01:36 sys
drwxrwxrwt. 7 root root 145 Jun 11 02:35 tmp
drwxr-xr-x. 12 root root 144 Jun 11 02:35 usr
drwxr-xr-x. 20 root root 262 Jun 11 02:35 var
drwxr-xr-x. 2 root root 6 Jun 23 03:31 volume01 #生成镜像时自动挂载的数据卷目录
drwxr-xr-x. 2 root root 6 Jun 23 03:31 volume02 #生成镜像时自动挂载的数据卷目录
## 这两个卷一定有一个与外部同步的目录
# 在卷目录下创建一个文件
[root@1af48762856e /]# cd volume01/
[root@1af48762856e volume01]# touch container.txt
# 在宿主机上查看此容器的元数据可以看到卷挂载到了外部的某个目录下
[root@k8s-master docker-test-volume]# docker inspect 1af48762856e
...
"Mounts": [
{
"Type": "volume",
"Name": "588dd712d0817140680bd2d7fad6d85bf837cbf9f1ad8c435d06ff98d076f259",
"Source": "/var/lib/docker/volumes/588dd712d0817140680bd2d7fad6d85bf837cbf9f1ad8c435d06ff98d076f259/_data",
"Destination": "volume02",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
},
{
"Type": "volume",
"Name": "fbd1a9f5c760ef7b592c4b31aaaa3ab4887d650b40397476012d4d942b151bc6",
"Source": "/var/lib/docker/volumes/fbd1a9f5c760ef7b592c4b31aaaa3ab4887d650b40397476012d4d942b151bc6/_data",
"Destination": "volume01",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
# 可以看到volume01的挂载目录是路径,cd切换到目录下查看已经同步了创建的文件
/var/lib/docker/volumes/fbd1a9f5c760ef7b592c4b31aaaa3ab4887d650b40397476012d4d942b151bc6/_data/
[root@k8s-master _data]# ll
total 0
-rw-r--r--. 1 root root 0 Jun 23 11:35 container.txt
通常构建自己的镜像时,没有挂在卷,要手动镜像挂载 -v 卷名:容器内路径
6. 数据卷容器
创建三台容器来进行测验数据卷共享 (使用刚刚通过dockerfile生成的镜像)
--volumes-from # 只要通过此参数,则可以实现容器间的数据共享
# 创建第一台容器docker01,挂载的数据卷下没有内容
[root@k8s-master ~]# docker run -it --name docker01 lichenxing/centos:1.0
[root@eac7afb4cb11 /]# ls -l
total 0
....
drwxr-xr-x. 2 root root 6 Jun 23 05:54 volume01
drwxr-xr-x. 2 root root 6 Jun 23 05:54 volume02
[root@eac7afb4cb11 /]# ls volume01
[root@eac7afb4cb11 /]# ls volume02
# 创建的第二台容器docker02,挂载的为docker上的数据卷,也没有内容
[root@k8s-master ~]# docker run -it --name docker02 --volumes-from docker01 lichenxing/centos:1.0
[root@a493d7a3d2ca /]# ls -l
total 0
....
drwxr-xr-x. 2 root root 6 Jun 23 05:54 volume01
drwxr-xr-x. 2 root root 6 Jun 23 05:54 volume02
[root@a493d7a3d2ca /]# ls volume01
[root@a493d7a3d2ca /]# ls volume02
# 在docker01容器上的数据卷目录创建文件
[root@k8s-master ~]# docker attach docker01
[root@eac7afb4cb11 /]# touch /volume01/docker01
# 在docker02容器上查看,docker01的数据卷目录下文件也已经同步过来了
[root@k8s-master ~]# docker attach docker02
[root@a493d7a3d2ca /]# ls /volume01/
docker01
# 创建第三台容器docker03,将docker01的数据卷挂载; 并且再创建一个docker03文件
# 可以发现容器docker01上的数据卷内容都同步了
[root@k8s-master ~]# docker run -it --name docker03 --volumes-from docker01 lichenxing/centos:1.0
[root@336c364cb4fa /]# ls -l /volume01/
total 0
-rw-r--r--. 1 root root 0 Jun 23 06:01 docker01
[root@336c364cb4fa /]# touch /volume01/docker03
# 在容器docker01上查看也同步了
[root@k8s-master ~]# docker attach docker01
[root@eac7afb4cb11 /]# ls -l volume01/
total 0
-rw-r--r--. 1 root root 0 Jun 23 06:01 docker01
-rw-r--r--. 1 root root 0 Jun 23 06:07 docker03
删除容器docker01后,其他容器的数据卷内容没有丢失-拷贝机制
[root@k8s-master ~]# docker rm -f docker01
docker01
[root@k8s-master ~]# docker attach docker02
[root@a493d7a3d2ca /]# ls -l /volume01/
total 0
-rw-r--r--. 1 root root 0 Jun 23 06:01 docker01
-rw-r--r--. 1 root root 0 Jun 23 06:07 docker03
[root@a493d7a3d2ca /]# read escape sequence
[root@k8s-master ~]# docker attach docker03
[root@336c364cb4fa /]# ls -l /volume01/
total 0
-rw-r--r--. 1 root root 0 Jun 23 06:01 docker01
-rw-r--r--. 1 root root 0 Jun 23 06:07 docker03
[root@336c364cb4fa /]# read escape sequence
可以运用在多个mysql实现数据共享
# 例子 mysql01
[root@k8s-master ~]# docker run -d -p 3310:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
# 例子 mysql02; 挂载mysql01的数据卷
[root@k8s-master ~]# docker run -d -p 3310:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql01 mysql:5.7
结论
- 容器之间配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止。
- 一旦持久化到本地目录,本地的数据是不会删除的。
九、Dockerfile
1. Dockerfile介绍
dockerfile 就是用来构建docker镜像的构建文件! 命令脚本!
构建步骤:
- 编写一个dockerfile文件
- docker build构建成为一个镜像
- docker run 运行镜像
- docker push 发布镜像(dockerHub、私有仓库)
image
很多官方镜像都是基础包,很多功能没有,我们通常会自己搭建自己的镜像!
2. Dockerfile构建
基础知识
- 每个指令都必须是大写字母
- 执行从上到下顺序执行
- "#"表示注释
- 每一个指令都会创建提交一个新的镜像层,并提交!
- 在 Docker 17.05 以上版本中,可以使用多阶段构建 来减少所构建镜像的大小。
image
- Dockerfile是面向开发,我们以后要发布项目,做镜像,就需要编写dockerfile文件。
- Docker镜像逐渐成为企业交付的标准。
- Dockerfile :构建文件,定义了一切的步骤,源代码。
- DockerImages:通过DockerFile构建生成的镜像,最终发布和运行的产品,原来是jar包 war包
- Docker容器:容器就是镜像运行起来提供的服务器
3. Dockerfile的指令
FROM #指定基础镜像
MAINTAINER #指定镜像创建者信息(姓名+邮箱)
RUN #执行构建命令
CMD #设置容器启动时执行的操作(只有最后一个会生效,可被替代)
ENTRYPOINT #设置容器启动时执行的操作(可以追加命令)
USER #设置容器的用户
EXPOSE #指定容器需要映射到宿主机的端口
ENV #用于设置环境变量
ADD #从src复制文件到容器的dest路径(会自动解压tar包)
VOLUME #指定挂载点
WORKDIR #工作目录
ONBUILD #在子镜像中执行,构建一个被继承,就会运行此指令,触发指令
COPY #类似ADD,将文件拷贝到镜像中(不会解压tar包)
image
4. 自己写一个Dockerfile文件构建镜像
Docker Hub中,99%镜像都是从这个基础镜像
FROM scratch
过来的,然后配置需要的软件和配置进行构建。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。如果你以scratch
为基础镜像的话,意味着不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在。有的人可能感觉很奇怪,没有任何基础镜像,我怎么去执行我的程序呢,其实对于 Linux 下静态编译的程序来说,并不需要有操作系统提供运行时支持,所需的一切库都已经在可执行文件里了,因此直接FROM scratch
会让镜像体积更加小巧。
# 创建一个存放dockerfile文件的目录
mkdir -p /home/dockerfile
cd /home/dockerfile/
# 编写dockerfile文件
[root@k8s-master dockerfile]# cat mydockerfile-centos
FROM centos
MAINTAINER lichenxing<245684979@qq.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 80
CMD echo $MYPATH
CMD echo "---end---"
CMD /bin/bash
# 进行构建
#docker build "."最后的"."号,其实是在指定镜像构建过程中的上下文环境的目录
docker build -f [dockerfile文件路径] -t 镜像名:[tag] .
[root@k8s-master dockerfile]#docker build -f mydockerfile-centos -t mycentos:0.1 .
....
Successfully built 754ab894cdb8
Successfully tagged mycentos:0.1
# 查看构建成功的镜像
[root@k8s-master dockerfile]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mycentos 0.1 754ab894cdb8 3 minutes ago 295MB
测试运行
## 这是构建之前的官方centos镜像
[root@k8s-master dockerfile]# docker run -it centos
[root@5a792ccff9b2 /]# pwd #工作目录默认根目录
/
[root@5a792ccff9b2 /]# vim #没有vim命令
bash: vim: command not found
[root@5a792ccff9b2 /]# ifconfig #没有ifconfig命令
bash: ifconfig: command not found
## 这是通过dockerfile构建完成的镜像mycentos:0.1
[root@k8s-master dockerfile]# docker run -it mycentos:0.1
[root@8ebed8ffcb20 local]# pwd ##工作目录修改为/usr/local
/usr/local
[root@8ebed8ffcb20 local]# which vim #有vim命令
/usr/bin/vim
[root@8ebed8ffcb20 local]# which ifconfig #有ifconfig命令
/usr/sbin/ifconfig
查看镜像的构建历史记录
image
通过此方法,可以在拿到一个镜像时,研究一下是怎么做到的
5. RUN 执行命令
是否可以像 Shell 脚本一样把每个命令对应一个 RUN 呢?
- Dockerfile 中每一个指令都会建立一层,RUN 也不例外。每一个 RUN 的行为,就和刚才我们手工建立镜像的过程一样:新建立一层,在其上执行这些命令,执行结束后,commit 这一层的修改,构成新的镜像。
- 每个指令新建一层这是完全没有意义的,而且很多运行时不需要的东西,都被装进了镜像里,比如编译环境、更新的软件包等等。结果就是产生非常臃肿、非常多层的镜像,不仅仅增加了构建部署的时间,也很容易出错。 这是很多初学 Docker 的人常犯的一个错误。
- Union FS 是有最大层数限制的,比如 AUFS,曾经是最大不得超过 42 层,现在是不得超过 127 层。
- 一些下载 创建 删除的命令没有必要建立很多层,这只是一层的事情。因此,这里没有使用很多个 RUN 对一一对应不同的命令,而是仅仅使用一个 RUN 指令,并使用
&&
将各个所需命令串联起来,简化为1层。 - 在撰写 Dockerfile 的时候,要经常提醒自己,这并不是在写 Shell 脚本,而是在定义每一层该如何构建。
- 最后建议添加清理的命令,删除为了编译构建所需要的各种软件,清理所有下载、展开的文件,缓存文件。这是很重要的一步,镜像是多层存储,每一层的东西并不会在下一层被删除,会一直跟随着镜像。因此镜像构建时,一定要确保每一层只添加真正需要添加的东西,任何无关的东西都应该清理掉。制作出了很臃肿的镜像的原因之一,就是忘记了每一层构建的最后一定要清理掉无关文件。
6. CMD 和 ENTRYPOINT 区别
CMD #设置容器启动时执行的操作(只有最后一个会生效,可被替代)
ENTRYPOINT #设置容器启动时执行的操作(可以追加命令)
测试 CMD
# 编写一个简单的CMD的dockerfile文件
[root@k8s-master dockerfile]# cat dockerfile-cmd-test
FROM centos
CMD ["ls","-a"]
# 进行构建镜像
[root@k8s-master dockerfile]# docker build -f dockerfile-cmd-test -t cmdtest .
....
Successfully built 0a29d7f31b12
Successfully tagged cmdtest:latest
# 运行一个CMD镜像的容器,可以看到,直接输出dockerfile中写的CMD指令
[root@k8s-master dockerfile]# docker run cmdtest
.
..
.dockerenv
bin
dev
etc
home
...
# 再次运行容器,最近一个命令"-l" [ls -al]
[root@k8s-master dockerfile]# docker run cmdtest -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "exec: \"-l\": executable file not found in $PATH": unknown.
## CMD的清理向下"-l"替换了CMD ["ls","-a"]命令, "-l"不是命令所以会报错
[root@k8s-master dockerfile]# docker run cmdtest ls -al
total 0
drwxr-xr-x. 1 root root 6 Jun 23 09:41 .
drwxr-xr-x. 1 root root 6 Jun 23 09:41 ..
-rwxr-xr-x. 1 root root 0 Jun 23 09:41 .dockerenv
lrwxrwxrwx. 1 root root 7 May 11 2019 bin -> usr/bin
drwxr-xr-x. 5 root root 340 Jun 23 09:41 dev
drwxr-xr-x. 1 root root 66 Jun 23 09:41 etc
drwxr-xr-x. 2 root root 6 May 11 2019 home
....
测试 ENTRYPOINT
# 编写一个ENTRYPOINT的dockerfile文件
[root@k8s-master dockerfile]# cat dockerfile-cmd-entrypoint
FROM centos
ENTRYPOINT ["ls","-a"]
# 进行构建镜像
[root@k8s-master dockerfile]# docker build -f dockerfile-cmd-entrypoint -t entrypoint .
....
Successfully built 120ba8d637f5
Successfully tagged entrypoint:latest
# 运行一个ENTRYPOINT镜像的容器,发现和CMD没有区别
[root@k8s-master dockerfile]# docker run entrypoint
.
..
.dockerenv
bin
dev
etc
home
....
# 再次运行容器,追加一个参数 "-l";会发现直接就输出了详细信息
# 追加的命令,是直接拼接在 ENTRYPOINT 命令的后面,而不会去替换命令
[root@k8s-master dockerfile]# docker run entrypoint -l
total 0
drwxr-xr-x. 1 root root 6 Jun 23 09:48 .
drwxr-xr-x. 1 root root 6 Jun 23 09:48 ..
-rwxr-xr-x. 1 root root 0 Jun 23 09:48 .dockerenv
lrwxrwxrwx. 1 root root 7 May 11 2019 bin -> usr/bin
drwxr-xr-x. 5 root root 340 Jun 23 09:48 dev
drwxr-xr-x. 1 root root 66 Jun 23 09:48 etc
drwxr-xr-x. 2 root root 6 May 11 2019 home
....
Dockerfile中很多命令都十分的相似,我们需要了解他们的区别,最好的学习方法就是对比它们。
7. 测试 Tomcat镜像(ADD COPY)
1. 准备镜像文件,tomcat压缩包,jdk的压缩包
image
2. 编写dockerfile文件
建议官方命名 Dockerfile
;build
时就不需要-f
指定了
image
[root@k8s-master tomcat]# cat Dockerfile
FROM centos
MAINTAINER lichenxing<245684979@qq.com>
COPY readme.txt /usr/local/readme.txt
ADD jdk-8u60-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-8.0.27.tar.gz /usr/local/
RUN yum -y install vim
ENV MYPATH /usr/local
WORKDIR $MYPATH
ENV JAVA_HOME /usr/local/jdk1.8.0_60
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-8.0.27
ENV CATALINA_BASH /usr/local/apache-tomcat-8.0.27
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
EXPOSE 8080
CMD /usr/local/apache-tomcat-8.0.27/bin/startup.sh && tail -F /url/local/apache-tomcat-8.0.27/bin/logs/catalina.out
3. 构建镜像
[root@k8s-master tomcat]# pwd
/home/dockerfile/build/tomcat
[root@k8s-master tomcat]# docker build -t diytomcat ./
....
Successfully built e256e862f380
Successfully tagged diytomcat:latest
image
4. 运行此镜像的容器
# 将webapps目录下的一些日志或者代码可以挂载到宿主机的目录下
[root@k8s-master tomcat]# docker run -d -p 9090:8080 --name lcxtomcat -v /home/dockerfile/build/tomcat/test:/usr/local/apache-tomcat-8.0.27/webapps/test -v /home/dockerfile/build/tomcat/tomcatlogs:/usr/local/apache-tomcat-8.0.27/logs/ diytomcat
f1c38b290af2d88ca5ccfc99b5baaea77cc43d9de6a8ce75d6443125f74d2c3a
# 可以看到挂载到宿主机的目录已经同步
[root@k8s-master tomcat]# pwd
/home/dockerfile/build/tomcat
[root@k8s-master tomcat]# ls
apache-tomcat-8.0.27.tar.gz Dockerfile jdk-8u60-linux-x64.tar.gz readme.txt test tomcatlogs
[root@k8s-master tomcat]# ll tomcatlogs/
total 20
-rw-r--r--. 1 root root 6539 Jun 24 17:41 catalina.2020-06-24.log
-rw-r--r--. 1 root root 6539 Jun 24 17:41 catalina.out
-rw-r--r--. 1 root root 0 Jun 24 17:41 host-manager.2020-06-24.log
-rw-r--r--. 1 root root 280 Jun 24 17:41 localhost.2020-06-24.log
-rw-r--r--. 1 root root 0 Jun 24 17:41 localhost_access_log.2020-06-24.txt
-rw-r--r--. 1 root root 0 Jun 24 17:41 manager.2020-06-24.log
5. 进入tomcat容器中查看
[root@k8s-master tomcat]# docker exec -it lichenxingtomcat /bin/bash
[root@f1c38b290af2 local]# pwd
/usr/local
[root@f1c38b290af2 local]# ls
apache-tomcat-8.0.27 etc include lib libexec sbin src
bin games jdk1.8.0_60 lib64 readme.txt share
[root@f1c38b290af2 local]# ls -l apache-tomcat-8.0.27/
total 92
-rw-r--r--. 1 root root 57011 Sep 28 2015 LICENSE
-rw-r--r--. 1 root root 1444 Sep 28 2015 NOTICE
-rw-r--r--. 1 root root 6741 Sep 28 2015 RELEASE-NOTES
-rw-r--r--. 1 root root 16204 Sep 28 2015 RUNNING.txt
drwxr-xr-x. 2 root root 4096 Sep 28 2015 bin
drwxr-xr-x. 1 root root 22 Jun 24 09:41 conf
drwxr-xr-x. 2 root root 4096 Sep 28 2015 lib
drwxr-xr-x. 2 root root 197 Jun 24 09:41 logs
drwxr-xr-x. 2 root root 30 Sep 28 2015 temp
drwxr-xr-x. 1 root root 18 Jun 24 09:41 webapps
drwxr-xr-x. 1 root root 22 Jun 24 09:41 work
[root@f1c38b290af2 local]# ls -l apache-tomcat-8.0.27/webapps/
total 8
drwxr-xr-x. 3 root root 4096 Sep 28 2015 ROOT
drwxr-xr-x. 14 root root 4096 Sep 28 2015 docs
drwxr-xr-x. 6 root root 83 Sep 28 2015 examples
drwxr-xr-x. 5 root root 87 Sep 28 2015 host-manager
drwxr-xr-x. 5 root root 103 Sep 28 2015 manager
drwxr-xr-x. 2 root root 6 Jun 24 09:41 test
[root@f1c38b290af2 local]# ls -l apache-tomcat-8.0.27/logs/
total 20
-rw-r--r--. 1 root root 6539 Jun 24 09:41 catalina.2020-06-24.log
-rw-r--r--. 1 root root 6539 Jun 24 09:41 catalina.out
-rw-r--r--. 1 root root 0 Jun 24 09:41 host-manager.2020-06-24.log
-rw-r--r--. 1 root root 280 Jun 24 09:41 localhost.2020-06-24.log
-rw-r--r--. 1 root root 0 Jun 24 09:41 localhost_access_log.2020-06-24.txt
-rw-r--r--. 1 root root 0 Jun 24 09:41 manager.2020-06-24.log
# 测试连接性
[root@f1c38b290af2 local]# curl -I 127.0.0.1:8080
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 24 Jun 2020 09:48:16 GMT
宿主机的9090端口
image
6. 上传一个web站点的压缩包到test目录下进行测试
[root@k8s-master tomcat]# pwd
/home/dockerfile/build/tomcat
[root@k8s-master tomcat]# cd ./test/
[root@k8s-master test]# ll
total 20316
-rw-r--r--. 1 root root 20797013 Jun 24 18:02 jpress-web-newest.war
drwxr-xr-x. 3 root root 38 Sep 19 2016 META-INF
-rw-r--r--. 1 root root 96 Jul 27 2016 robots.txt
drwxr-xr-x. 11 root root 139 Sep 19 2016 static
drwxr-xr-x. 4 root root 31 Sep 19 2016 templates
drwxr-xr-x. 6 root root 75 Jun 24 18:02 WEB-INF
image
先不用做安装,只测试。没有数据库环境
- 在主机的test目录下就可以修改代码文件。
# 可以在宿主机上直接查看访问的日志文件
[root@k8s-master tomcat]# tail -f tomcatlogs/catalina.out
JFinal action report -------- 2020-06-24 10:05:59 ------------------------------
Controller : io.jpress.install.InstallController.(InstallController.java:1)
Method : step2
Interceptor : io.jpress.core.interceptor.JI18nInterceptor.(JI18nInterceptor.java:1)
io.jpress.interceptor.GlobelInterceptor.(GlobelInterceptor.java:1)
io.jpress.interceptor.AdminInterceptor.(AdminInterceptor.java:1)
io.jpress.core.interceptor.HookInterceptor.(HookInterceptor.java:1)
io.jpress.install.InstallInterceptor.(InstallInterceptor.java:1)
--------------------------------------------------------------------------------
8. 发布镜像到DockerHub
官方DockerHub仓库
需要注册自己的账户,确认可以登录
image
在服务器上提交镜像到官方仓库
[root@k8s-master tomcat]# docker login -u 245684979
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
# 为封装好的镜像打一个标签
# 这里要注意 给自己镜像命名的时候格式应该是: docker注册用户名/镜像名,不然是push不上去的
[root@k8s-master tomcat]# docker tag diytomcat:latest 245684979/diytomcat:1.0
image
[root@k8s-master tomcat]# docker push 245684979/diytomcat:1.0
The push refers to repository [docker.io/245684979/diytomcat]
0877995fc452: Pushing 9.192MB/57.19MB
5dedcbd44b60: Pushing 2.864MB/12.94MB
f675325f4324: Pushing 1.607MB/364.8MB
c966da79fa06: Pushing 2.56kB
eb29745b8228: Pushing 6.019MB/215.3MB
...
提交的时候也是按照镜像的层级来进行提交的,提交成功后在DockerHub就可以看到了
image
9. 发布镜像到阿里云镜像仓库
登陆阿里云
找到容器镜像服务
创建命名空间
创建容器镜像
浏览操作指南
image
[root@k8s-master ~]# docker push registry.cn-beijing.aliyuncs.com/lichenxing/lcxtomcat:1.0
The push refers to repository [registry.cn-beijing.aliyuncs.com/lichenxing/lcxtomcat]
0877995fc452: Pushed
5dedcbd44b60: Pushed
f675325f4324: Pushed
c966da79fa06: Pushed
eb29745b8228: Pushed
1.0: digest: sha256:2e3c25e752897e3c166cc3b372bddefb3de5db0fb04d1f8a883580e04bdd6c90 size: 1372
10. 发布镜像到私有仓库
有时候使用 Docker Hub 这样的公共仓库可能不方便,用户可以创建一个本地仓库供私人使用。docker-registry
是官方提供的工具,可以用于构建私有的镜像仓库。
普通的registry
默认情况下,仓库会被创建在容器的/var/lib/registry
目录下。可以通过 -v 参数来将镜像文件存放在本地的指定路径。
# 运行官方registry镜像
docker run -d -p 5000:5000 --restart=always --name registry -v /opt/myregistry:/var/lib/registry registry
# 将镜像加速器地址改为本地
[root@k8s-master ~]# cat /etc/docker/daemon.json
{
"registry-mirrors": ["https://registry.docker-cn.com"],
"insecure-registries": ["192.168.0.10:5000"]
}
systemctl restart docker
# 给镜像打标签
docker tag diytomcat 192.168.0.10:5000/lcxtomcat:1.0
# 上传镜像到私有仓库
[root@k8s-master ~]# docker push 192.168.0.10:5000/lcxtomcat
The push refers to repository [192.168.0.10:5000/lcxtomcat]
0877995fc452: Pushed
5dedcbd44b60: Pushed
f675325f4324: Pushed
c966da79fa06: Pushed
eb29745b8228: Pushed
1.0: digest: sha256:2e3c25e752897e3c166cc3b372bddefb3de5db0fb04d1f8a883580e04bdd6c90 size: 1372
# 查看私有仓库上传的镜像
[root@k8s-master ~]# curl 127.0.0.1:5000/v2/_catalog
{"repositories":["lcxtomcat"]}
十、企业级镜像仓库 Harbor
https://github.com/goharbor/harbor/tree/release-2.0.0
Habor是由VMWare公司开源的容器镜像仓库。事实上,Habor是在Docker Registry上进行了相应的 企业级扩展,从而获得了更加广泛的应用,这些新的企业级特性包括:管理用户界面,基于角色的访 问控制 ,AD/LDAP集成以及审计日志等,足以满足基本企业需求。
下载地址:https://github.com/goharbor/harbor/releases
软件版本
- 在Linux主机上: docker 17.06.0-ce +和docker-compose 1.18.0+
1. 安装
#安装docker compose
yum install -y docker-compose
docker-compose --version
docker-compose version 1.18.0, build 8dd22a9
#这里使用1.9版本的harbor
tar xf harbor-offline-installer-v1.9.1.tgz -C /opt/
cd /opt/harbor/
# 修改配置文件
vim harbor.yml
hostname: 192.168.0.10
harbor_admin_password: 123456
#执行prepare脚本
./prepare
#执行脚本
sh install.sh
[Step 0]: checking installation environment ...
Note: docker version: 19.03.11
Note: docker-compose version: 1.18.0
[Step 1]: loading Harbor images ...
2. 访问
admin 123456
3. 推送镜像
docker tag nginx:1.18.0 192.168.0.10/library/nginx:1.18.0
#修改daemon.json配置文件,指定仓库IP为192.168.0.10
vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://registry.docker-cn.com"],
"insecure-registries": ["192.168.0.10"]
}
systemctl restart docker
docker-compose up -d
4. 添加新用户
#登陆普通用户guest
[root@k8s-master harbor]# docker login 192.168.0.10
Username: guest
Password: #Lcx123456
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
推送镜像
#推送其他镜像到harbor
##nginx
[root@k8s-master harbor]# docker push 192.168.0.10/library/nginx:1.18.0
The push refers to repository [192.168.0.10/library/nginx]
97d4365452ad: Pushed
d1c9311342b8: Pushed
edf3aa290fb3: Pushed
1.18.0: digest: sha256:15b2135c75230e8282f9c3039fd50f22e90929eafc827f6b8d629bbe190c33d0 size: 952
## php
docker tag php:v2 192.168.0.10/library/php:v2
docker push 192.168.0.10/library/php:v2
## tomcat
docker tag tomcat:v2 192.168.0.10/library/tomcat:v2
docker push 192.168.0.10/library/tomcat:v2
## mysql
docker tag mysql:5.7 192.168.0.10/library/mysql:5.7
docker push 192.168.0.10/library/mysql:5.7
5. 创建私有项目project
#登出
docker logout
>/root/.docker/config.json
#登陆admin用户
WARNING: Error loading config file: /root/.docker/config.json: EOF
Username: admin
Password: #123456
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
#上传一个镜像
docker tag tomcat:v2 192.168.0.10/project/tomcat:v2
docker push 192.168.0.10/project/tomcat:v2
十一、Docker网络
- None:不为容器配置任何网络功能,--net=none
- Container:与另一个运行中的容器共享Network Namespace,--net=container:containerID(K8S)
- Host:与宿主机共享Network Namespace,--network=host 性能最高
- Bridge:Docker设计的NAT网络模型(默认)
# 清除所有容器和镜像环境
docker rm -f $(docker ps -aq)
docker rmi `docker images -qa`
# 启动一台容器
[root@k8s-master ~]# docker run -d -P --name tomcat01 tomcat
# 查看容器的网卡信息
[root@k8s-master ~]# docker exec -it tomcat01 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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
21: eth0@if22: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
# linux宿主机可以ping通容器内部
[root@k8s-master ~]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.060 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.053 ms
原理:
- 每启动一个docker容器,docker都会给容器分配一个ip,我们只要按照了docker,就会有一个网卡docker0,Bridge桥接模式使用的技术是
evth-pair
技术。 - evth-pair 就是一对的虚拟设备接口,他们都是成对出现的,一段连着协议,一段彼此相连,正因为有这个特性,evth-pair充当一个桥梁,专门连接各种虚拟网络设备。每开启运行一个容器,就会增加一对儿对应的网卡。
- Openstack、Docker、OVS都是使用的 evth-pair技术。
- 容器删除,对应的网桥也被删除
1. Bridge模式
当Docker
进程启动时,会在主机上创建一个名为docker0
的虚拟网桥,此主机上启动的Docker
容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。从docker0
子网中分配一个 IP 给容器使用,并设置 docker0 的 IP 地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair
设备,Docker 将 veth pair 设备的一端放在新创建的容器中,并命名为eth0
(容器的网卡),另一端放在主机中,以vethxxx
这样类似的名字命名,并将这个网络设备加入到 docker0 网桥中。可以通过brctl show
命令查看。
bridge
模式是 docker 的默认网络模式,不写–net
参数,就是bridge
模式。使用docker run -p
时,docker 实际是在iptables
做了DNAT
规则,实现端口转发功能。可以使用iptables -t nat -vnL
查看。
image
--link 容器互联
随着 Docker 网络的完善,强烈建议大家将容器加入自定义的 Docker 网络来连接多个容器,而不是使用 --link 参数。
思考:编写一个微服务,database url=ip:,项目不重启,数据库ip换掉了,我们希望可以处理这个问题,可以用名字来进行访问容器吗?
# 创建俩台容器 tomcat01和tomcat02
docker run -it -d -P --name tomcat01 245684979/diytomcat:1.0
docker run -it -d -P --name tomcat02 245684979/diytomcat:1.0
# 尝试相互ping不能ping通
[root@k8s-master ~]# docker exec -it tomcat02 ping tomcat01
ping: tomcat01: Name or service not known
# 创建tomcat03容器,使用--link,即可解决了网络连通问题
docker run -it -d -P --name tomcat03 --link tomcat02 245684979/diytomcat:1.0
# 通过容器tomcat03来ping容器tomcat02可以ping通了
[root@k8s-master ~]# docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.17.0.3) 56(84) bytes of data.
64 bytes from tomcat02 (172.17.0.3): icmp_seq=1 ttl=64 time=0.055 ms
# 反向是不可以ping通 02 ping 03
[root@k8s-master ~]# docker exec -it tomcat02 ping tomcat03
ping: tomcat03: Name or service not known
查看网络的信息
# 查看网络详细信息
[root@k8s-master ~]# docker network inspect cd3809ba6584
[
{
"Name": "bridge",
"Id": "cd3809ba6584494c86e9802d3dfc6424bb33226c93b80bd31d9f43dd25c200c2",
"Created": "2020-06-29T11:20:18.826585474+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"07926c954f2ad324dc977bed26af4953713355dcc5b67aea97f18830984bfce5": {
"Name": "tomcat02",
"EndpointID": "ff5fc39a60e1c6291afed28de6c2d14a5c43554e9a6dbff04495ee4d4ae0ec64",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16", # 为tomcat02分配的IP
"IPv6Address": ""
},
"b423584cb2f658703f42bfc8fe9fe40e61b3b9b7d29d4bee5af213340e9058ae": {
"Name": "tomcat01",
"EndpointID": "2e6d7bf8db206b2392eec7b959c5c695e61e1826e1eb03f3e8d0d012b3a3cc63",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16", # 为tomcat01分配的IP
"IPv6Address": ""
},
"b820e4afdccdb8a50045c77de6e575bff0df692ed144673e2cb2bb2259a76c08": {
"Name": "tomcat03",
"EndpointID": "d7bf4b2f4b213f6497cfcfdac40c827d104f56dee5a6cd14fade2b48d8ae9f54",
"MacAddress": "02:42:ac:11:00:04",
"IPv4Address": "172.17.0.4/16", # 为tomcat03分配的IP
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
]
# 查看tomcat03的信息,可以看到links指定的是tomcat02
[root@k8s-master ~]# docker inspect tomcat03
....
"Links": [
"/tomcat02:/tomcat03/tomcat02"
],
....
# 通过查看tomcat03的hosts文件也可以看到
[root@k8s-master ~]# docker exec -it tomcat03 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.17.0.3 tomcat02 07926c954f2a # 指定了tomcat02
172.17.0.4 b820e4afdccd
--link
就是在hosts配置中增加了一个主机名的解析- 随着 Docker 网络的完善,建议将容器加入自定义的 Docker 网络来连接多个容器,而不是使用 --link 参数
- docker0问题 不支持容器名连接访问。
自定义网络
查看网络
# 查看网络
[root@k8s-master ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
cd3809ba6584 bridge bridge local
018532904f4e host host local
edfe5b0c21a1 none null local
# 清除测试的所有容器
docker rm -f $(docker ps -aq)
# 创建一台容器; --network brigde 就是docker0
docker run -d -P --name tomcat01 --network bridge tomcat
# 创建一个网络mynet
# --driver : 网络模式
# --subnet : 子网地址
# --gateway : 子网的网关地址
docker network create --driver bridge --subnet 172.20.0.0/16 --gateway 172.20.0.1 mynet
# 查看自己创建的网络详细信息
[root@k8s-master ~]# docker network inspect mynet
[
{
"Name": "mynet",
"Id": "ea720ae53f20b83193bca0c1dbb6296165539aa4c547f1ef37028e705b87da6c",
"Created": "2020-06-29T14:33:22.194817791+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.20.0.0/16", #子网
"Gateway": "172.20.0.1" #网关
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
启动两台容器;指定创建的自定义网络
docker run -d -P --name tomcat-net01 --net mynet tomcat
docker run -d -P --name tomcat-net02 --net mynet tomcat
# 再次查看网络详情,可以看到启动的容器的IP
[root@k8s-master ~]# docker network inspect mynet
....
"Containers": {
"2767e468d20157e43b67174eeef94267ce2b3a5b9f66446b24fd17c06549fdb3": {
"Name": "tomcat-net01",
"EndpointID": "abadd831f2591a0d2aed089abac60292cfc0925193d6f3394131955140118750",
"MacAddress": "02:42:ac:14:00:02",
"IPv4Address": "172.20.0.2/16",
"IPv6Address": ""
},
"4a70bba89baf3e98b4f3e35de9ee19d5363f06c592dff2bf81134fbc187ac0a0": {
"Name": "tomcat-net02",
"EndpointID": "8cdf9df77303ec7c3562e4b216d09ac5c5a39a7d7a5a1563b93ea7f5fd4d5060",
"MacAddress": "02:42:ac:14:00:03",
"IPv4Address": "172.20.0.3/16",
"IPv6Address": ""
}
},
# 再次测试ping连接; ping主机名也可以ping通了
[root@k8s-master ~]# docker exec -it tomcat-net01 ping 172.20.0.3
PING 172.20.0.3 (172.20.0.3) 56(84) bytes of data.
64 bytes from 172.20.0.3: icmp_seq=1 ttl=64 time=0.111 ms
[root@k8s-master ~]# docker exec -it tomcat-net01 ping tomcat-net02
PING tomcat-net02 (172.20.0.3) 56(84) bytes of data.
64 bytes from tomcat-net02.mynet (172.20.0.3): icmp_seq=1 ttl=64 time=0.042 ms
--------------------------------------
##现在不使用--link也可以ping通主机名了
自定义的网络docker都已经帮我们维护好了对应的关系,平时也推荐这样使用网络。
优势:
- Redis:不同的集群使用不同的网络,保证集群是安全和健康的
- MySQL:不同的集群使用不同的网络,保证集群是安全和健康的
2. Host 模式
如果启动容器的时候使用host
模式,那么这个容器将不会获得一个独立的Network Namespace
,而是和宿主机共用一个 Network Namespace。容器将不会虚拟出自己的网卡,配置自己的 IP 等,而是使用宿主机的 IP 和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。
image
# 运行一个host网络的容器
docker run -it -d -P --name tomcat-host01 --net host tomcat
# 查看此容器的ip地址和宿主机一致
[root@k8s-master ~]# docker exec -it tomcat-host01 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:8a:1a:eb brd ff:ff:ff:ff:ff:ff
inet 192.168.0.10/24 brd 192.168.0.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe8a:1aeb/64 scope link
valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:8a:1a:f5 brd ff:ff:ff:ff:ff:ff
inet 172.16.0.10/24 brd 172.16.0.255 scope global eth1
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe8a:1af5/64 scope link
valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:8d:a8:1d:4b brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:8dff:fea8:1d4b/64 scope link
valid_lft forever preferred_lft forever
21: br-45945e527658: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:16:06:bd:c9 brd ff:ff:ff:ff:ff:ff
inet 172.20.0.1/16 brd 172.20.255.255 scope global br-45945e527658
valid_lft forever preferred_lft forever
inet6 fe80::42:16ff:fe06:bdc9/64 scope link
valid_lft forever preferred_lft forever
3. Container 模式
这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。
image
# 运行一个centos镜像容器
[root@k8s-master ~]# docker run -it -d --name centos01 centos
[root@k8s-master ~]# docker exec -it centos01 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
28: eth0@if29: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
# 运行一个Container模式的容器; 指定centos01容器;查看网络
[root@k8s-master ~]# docker run -it -d --name centos-container --network container:centos01 centos
[root@k8s-master ~]# docker exec -it centos-container 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
28: eth0@if29: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
4. None模式
使用none
模式,Docker 容器拥有自己的 Network Namespace,但是,并不为Docker 容器进行任何网络配置。也就是说,这个 Docker 容器没有网卡、IP、路由等信息。需要我们自己为 Docker 容器添加网卡、配置 IP 等。
image
# 运行一个none模式的容器
docker run -it -d --name centos-none --network none centos
# 进入容器查看网卡发现没有ip地址
[root@k8s-master ~]# docker exec -it centos-none ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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
5. 网络连通
image
image
# 用bridge模式的容器去ping自定义网络的容器;发现ping不通,因为网络不同
[root@k8s-master ~]# docker exec -it tomcat01 ping tomcat-net01
ping: tomcat-net01: Name or service not known
测试 将默认 bridge 模式的容器 tomcat01 和 自定义 mynet 网络打通
docker network connect mynet tomcat01
# 查看mynet网络详情
docker network inspect mynet
image
# 一个容器 两个ip地址!
[root@k8s-master ~]# docker exec -it tomcat01 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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
32: eth0@if33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
40: eth1@if41: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:14:00:04 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.20.0.4/16 brd 172.20.255.255 scope global eth1
valid_lft forever preferred_lft forever
# 可以ping通了
[root@k8s-master ~]# docker exec -it tomcat01 ping tomcat-net01
PING tomcat-net01 (172.20.0.2) 56(84) bytes of data.
64 bytes from tomcat-net01.mynet (172.20.0.2): icmp_seq=1 ttl=64 time=0.045 ms
# 而其他的是依旧ping不通的
[root@k8s-master ~]# docker exec -it tomcat02 ping tomcat-net01
ping: tomcat-net01: Name or service not known
总结:如果要跨网络操作其他容器,就需要使用
docker network connect
连通。
6. 部署一个Redis集群
# 创建一个redis网络
docker network create redis --subnet 172.30.0.0/16
# 执行一下命令创建6套redis目录和配置文件
for port in $(seq 1 6);\
do \
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat << EOF >/mydata/redis/node-${port}/conf/redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.30.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done
[root@k8s-master ~]# tree /mydata/redis/
/mydata/redis/
├── node-1
│ └── conf
│ └── redis.conf
├── node-2
│ └── conf
│ └── redis.conf
├── node-3
│ └── conf
│ └── redis.conf
├── node-4
│ └── conf
│ └── redis.conf
├── node-5
│ └── conf
│ └── redis.conf
└── node-6
└── conf
└── redis.conf
# 依次启动6台redis容器
docker run -p 6371:6379 -p 16371:16379 --name redis-1 \
-v /mydata/redis/node-1/data:/data \
-v /mydata/redis/node-1/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.30.0.11 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker run -p 6372:6379 -p 16372:16379 --name redis-2 \
-v /mydata/redis/node-2/data:/data \
-v /mydata/redis/node-2/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.30.0.12 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker run -p 6373:6379 -p 16373:16379 --name redis-3 \
-v /mydata/redis/node-3/data:/data \
-v /mydata/redis/node-3/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.30.0.13 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker run -p 6374:6379 -p 16374:16379 --name redis-4 \
-v /mydata/redis/node-4/data:/data \
-v /mydata/redis/node-4/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.30.0.14 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker run -p 6375:6379 -p 16375:16379 --name redis-5 \
-v /mydata/redis/node-5/data:/data \
-v /mydata/redis/node-5/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.30.0.15 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker run -p 6376:6379 -p 16376:16379 --name redis-6 \
-v /mydata/redis/node-6/data:/data \
-v /mydata/redis/node-6/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.30.0.16 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
# 查看启动的redis容器
[root@k8s-master ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
85de61b9c858 redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 4 seconds ago Up 2 seconds 0.0.0.0:6376->6379/tcp, 0.0.0.0:16376->16379/tcp redis-6
0a1c84984623 redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 5 seconds ago Up 3 seconds 0.0.0.0:6375->6379/tcp, 0.0.0.0:16375->16379/tcp redis-5
747dc6d77115 redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 46 seconds ago Up 45 seconds 0.0.0.0:6374->6379/tcp, 0.0.0.0:16374->16379/tcp redis-4
0f88ca73c73a redis:5.0.9-alpine3.11 "docker-entrypoint.s…" About a minute ago Up About a minute 0.0.0.0:6373->6379/tcp, 0.0.0.0:16373->16379/tcp redis-3
3ca265147808 redis:5.0.9-alpine3.11 "docker-entrypoint.s…" About a minute ago Up About a minute 0.0.0.0:6372->6379/tcp, 0.0.0.0:16372->16379/tcp redis-2
c9b5fea846b9 redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 3 minutes ago Up 3 minutes 0.0.0.0:6371->6379/tcp, 0.0.0.0:16371->16379/tcp redis-1
# 创建redis集群
[root@k8s-master ~]# docker exec -it redis-1 /bin/sh
/data # redis-cli --cluster create 172.30.0.11:6379 172.30.0.12:6379 172.30.0.13:6379 172.30.0.14:637
79 172.30.0.15:6379 172.30.0.16:6379 --cluster-replicas 1
-------------------------
>>> 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.30.0.15:6379 to 172.30.0.11:6379
Adding replica 172.30.0.16:6379 to 172.30.0.12:6379
Adding replica 172.30.0.14:6379 to 172.30.0.13:6379
M: ef62648c7f22c87109e3a4004e0b7b2a9717c5ca 172.30.0.11:6379
slots:[0-5460] (5461 slots) master
M: 18eeb76c35d2185d39ecf0700cb486446f78065d 172.30.0.12:6379
slots:[5461-10922] (5462 slots) master
M: 89a2b7bc56f838794f3b4492745f33a55f2af842 172.30.0.13:6379
slots:[10923-16383] (5461 slots) master
S: 22acd8c91964e59f767fe95468210e876b65aa63 172.30.0.14:6379
replicates 89a2b7bc56f838794f3b4492745f33a55f2af842
S: 7d37c75d6f6868e0eb50505763c6dcca533a7252 172.30.0.15:6379
replicates ef62648c7f22c87109e3a4004e0b7b2a9717c5ca
S: c9726603df7d4a132ce012dd68ad829a69553ec9 172.30.0.16:6379
replicates 18eeb76c35d2185d39ecf0700cb486446f78065d
Can I set the above configuration? (type 'yes' to accept): yes #输入yes
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered. #集群配置完毕
# 查看redis集群
/data # redis-cli -c
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:85
cluster_stats_messages_pong_sent:88
cluster_stats_messages_sent:173
cluster_stats_messages_ping_received:83
cluster_stats_messages_pong_received:85
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:173
# 三主三从
127.0.0.1:6379> CLUSTER NODES
7d37c75d6f6868e0eb50505763c6dcca533a7252 172.30.0.15:6379@16379 slave ef62648c7f22c87109e3a4004e0b7b2a9717c5ca 0 1593426397000 5 connected
c9726603df7d4a132ce012dd68ad829a69553ec9 172.30.0.16:6379@16379 slave 18eeb76c35d2185d39ecf0700cb486446f78065d 0 1593426397015 6 connected
22acd8c91964e59f767fe95468210e876b65aa63 172.30.0.14:6379@16379 slave 89a2b7bc56f838794f3b4492745f33a55f2af842 0 1593426398022 4 connected
18eeb76c35d2185d39ecf0700cb486446f78065d 172.30.0.12:6379@16379 master - 0 1593426397518 2 connected 5461-10922
89a2b7bc56f838794f3b4492745f33a55f2af842 172.30.0.13:6379@16379 master - 0 1593426397518 3 connected 10923-16383
ef62648c7f22c87109e3a4004e0b7b2a9717c5ca 172.30.0.11:6379@16379 myself,master - 0 1593426396000 1 connected 0-5460
# 存一个值;可以看到存到了172.30.0.13,是master节点
127.0.0.1:6379> set a b
-> Redirected to slot [15495] located at 172.30.0.13:6379
OK
# 在其他窗口将redis-3 关闭
[root@k8s-master ~]# docker stop redis-3
redis-3
# 再次进入到redis集群查看之前的值;已经存到172.30.0.14节点上了
/data # redis-cli -c
127.0.0.1:6379> get a
-> Redirected to slot [15495] located at 172.30.0.14:6379
"b"
image
部署redis集群完成!
十二、 Docker Compose
Docker Machine
是Docker
官方编排(Orchestration)项目之一,负责在多种平台上快速安装 Docker 环境。
Docker Machine
项目基于Go
语言实现,目前在Github上进行维护。
Docker Machine
是 Docker 官方提供的一个工具,它可以帮助我们在远程的机器上安装 Docker,或者在虚拟机 host 上直接安装虚拟机并在虚拟机中安装 Docker。我们还可以通过 docker-machine
命令来管理这些虚拟机和 Docker。
yum install -y docker-compose
编写一个可道云的yml
[root@k8s-master docker]# cat docker-compose/wordpress/docker-compose.yml
version: '3'
services:
db:
image: mysql:5.7
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: somewordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
wordpress:
depends_on:
- db
image: wordpress:latest
volumes:
- web_data:/var/www/html
ports:
- "89:80"
restart: always
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
volumes:
db_data:
web_data:
#启动
docker-compose up
#后台启动
docker-compose up -d
十三、 Docker Swarm
Swarm
是使用SwarmKit构建的 Docker 引擎内置(原生)的集群管理和编排工具。提供 Docker 容器集群服务,是 Docker 官方对容器云生态进行支持的核心方案。
使用它,用户可以将多个 Docker 主机封装为单个大型的虚拟 Docker 主机,快速打造一套容器云平台。Swarm mode 内置 kv 存储功能,提供了众多的新特性,比如:具有容错能力的去中心化设计、内置服务发现、负载均衡、路由网格、动态伸缩、滚动更新、安全传输等。使得 Docker 原生的 Swarm 集群具备与Mesos
、Kubernetes
竞争的实力。
十四、Prometheus监控
1. 简介
Prometheus
是SoundCloud开源的一款开源软件。它的实现参考了Google内部的监控实现,与源自Google的Kubernetes结合起来非常合适。另外相比influxdb的方案,性能更加突出,而且还内置了报警功能。它针对大规模的集群环境设计了拉取式的数据采集方式,你只需要在你的应用里面实现一个metrics
接口,然后把这个接口告诉Prometheus
就可以完成数据采集了。
区别:
Zabbix
- 图形页面友好
- 成熟,资料较多
- 告警,分级,完善
- 架构成熟
Prometheus
- 不是很友好,各种配置都需要手写
- 对docker、k8s监控有成熟解决方案
特点:
- 多为数据模型:由度量名称和键值对标识的时间序列数据
- PromQL :一种灵活的查询语言,可以利用多维数据完成复杂的查询
- 不依赖分布式存储,单个服务器节点可直接工作
- 基于HTTP的pull方式采集时间序列数据
- 推送时间序列数据通过PushGateway组件支持
- 通过服务发现或静态配置发现目标
- 多种图形模式及仪表盘支持模式(grafana)
架构图
Prometheus Server:收集指标和存储时间序列数据,并提供查询接口
ClientLibrary:客户端库
Push Gateway:短期存储指标数据。主要用于临时性的任务
Exporters:采集已有的第三方服务监控指标并暴露metrics
Alertmanager:告警
Web UI:简单的Web控制台
image
2. 安装
Docker部署方式:https://prometheus.io/docs/prometheus/latest/installation/
prometheus配置文件解读:https://prometheus.io/docs/prometheus/latest/getting_started/
[root@k8s-master tmp]# cat /tmp/prometheus.yml
# my global config
global:
scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
# scrape_timeout is set to the global default (10s).
# Alertmanager configuration
alerting:
alertmanagers:
- static_configs:
- targets:
# - alertmanager:9093
# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
# - "first_rules.yml"
# - "second_rules.yml"
# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
# The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
- job_name: 'prometheus'
# metrics_path defaults to '/metrics'
# scheme defaults to 'http'.
static_configs:
- targets: ['localhost:9090']
启动容器
docker run -d \
--name prometheus \
-p 9090:9090 \
-v /tmp/prometheus.yml:/etc/prometheus/prometheus.yml \
prom/prometheus
image
image
3. cadvisor + prometheus + grafana
- docker cadvisor监控 + influxdb + grafana
- docker cadvisor监控 + prometheus + grafana
#添加cadvisor容器
docker run -d \
--volume=/:/rootfs:ro \
--volume=/var/run:/var/run:ro \
--volume=/sys:/sys:ro \
--volume=/var/lib/docker/:/var/lib/docker:ro \
--volume=/dev/disk/:/dev/disk:ro \
--publish=8080:8080 \
--detach=true \
--name cadvisor google/cadvisor:latest
#添加grafana容器
docker run -d \
--name grafana \
-p 3000:3000 \
grafana/grafana
image
在这里插入图片描述
#在/tmp目录下的prometheus.yml文件添加job
static_configs:
- targets: ['localhost:9090']
- job_name: "Linux_cadvisor"
static_configs:
- targets: ['192.168.0.10:8080']
- job_name: "Docker_grafana"
static_configs:
- targets: ['192.168.0.10:3000']
#重启下容器
docker restart prometheus
image
识别到cadvisor后即可查看数据
可以看出 prometheus 自身带的查询格式非常的难看
image
我们使用grafana来做展示数据;使用创建好的grafana容器
访问地址 192.168.0.10:3000
第一步 添加数据源
image
第二步 选择prometheus数据源
image
第三步 配置prometheus的访问地址
image
image
第四步 添加仪表盘
docker主机监控模板 193
linux主机监控模板 9276
image
image
第五步 监测Docker容器成功
image
第六步 监测linux主机
下载一个exporter
[root@k8s-master prometheus]# cat node_exporter.sh
#!/bin/bash
wget https://github.com/prometheus/node_exporter/releases/download/v0.17.0/node_exporter-0.17.0.linux-amd64.tar.gz
tar zxf node_exporter-0.17.0.linux-amd64.tar.gz
mv node_exporter-0.17.0.linux-amd64 /usr/local/node_exporter
cat <<EOF >/usr/lib/systemd/system/node_exporter.service
[Unit]
Description=https://prometheus.io
[Service]
Restart=on-failure
ExecStart=/usr/local/node_exporter/node_exporter
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable node_exporter
systemctl restart node_exporter
#默认启动9100端口
[root@k8s-master prometheus]# netstat -lntup|grep exporter
tcp6 0 0 :::9100 :::* LISTEN 61202/node_exporter
去prometheus的容器配置文件中添加上linux的exporter
[root@k8s-master tmp]# vim /tmp/prometheus.yml
...
- job_name: "Linux"
static_configs:
- targets: ['192.168.0.10:9100']
docker restart prometheus
image
然后就可以导入grafana模板 9276
image
image