Docker学习笔记
docker
云计算相关概念
什么是云计算
-
云计算是一种能够跨网络、按需提供基础架构、服务、平台和应用的交付方式,正在快速取代原本通过硬布线连接进行资源共享的方式。
-
云服务是指由第三方提供商托管的基础架构、平台或软件,可通过互联网提供给用户。 怎么选择云类型或云服务,取决于您的实际需求。世界上没有一模一样的两个云(即使它们的类型相同),也没有两个云服务解决的是同一个问题。但是,通过了解它们的相似之处,您可以更加清楚每种云计算类型和云服务可能会如何影响到您的业务。
云计算的类型
公共云:
一种利用非最终用户所有的资源创建的云环境,可重新分发给其他租户。全球规模最大的公共云提供商如:阿里云、Amazon Web Services(AWS)、Google云、IBM Cloud及Microsoft Azure等等。
公共云是一个虚拟资源池,可自动部署并通过自助服务界面在多个客户端间进行分配,其中的虚拟资源来自归第三方公司所有和管理的硬件设备。当工作负载出现意外需求波动时,可直接通过公共云进行横向扩展。
如今,公共云通常不会作为独立的基础架构解决方案来部署,而是被作为异构混合环境的一部分部署,这样即可以提高安全性和性能,降低成本,还可以改进基础架构、服务和应用的可用性。
私有云:
可广义地定义为:一种专为最终用户而创建,而且通常位于用户的防火墙内(有时也是内部部署)的云环境。
私有云是一种专为最终用户而创建,而且通常位于用户的防火墙内的云环境。尽管传统上私有云在内部运行,但现在许多企业构建的私有云位于供应商租赁的外部数据中心(IDC)内。
如果底层 IT 基础架构归某个拥有完全独立访问权限的客户专有,那这种云就是私有云。
混合云:
一种具有一定程度的工作负载可移植性以及编排和管理能力的多云环境。
混合云是一种IT架构,在两个或更多环境中进行某种程度的工作负载移植、编排和管理。混合云中的环境因企业而异,可能包括:
(1)至少1个私有云与至少1个公共云;
(2)含2个或多个相互连接的私有云;
(3)含2个或多个公共云;
(4)连接至少一个公共云或私有云的裸机或虚拟环境;
这些不同的要求源于云计算的早期阶段,那时,公共云与私有云之间的差异可通过位置和所有权明确区分。但是,现在的云类型更加复杂,因为位置和所有权比较抽象。这是因为很多云服务商为了节省成本,并不会自建机房,而是托管到IDC。
专有云:
专有云介于公有云和私有云之间,指的是由云服务提供商为单个客户提供专用的物理硬件和资源,但由云服务提供商负责管理和维护。这是一种租用云服务商的资源,但独享硬件的模式。
特点:
(1)独享物理资源:虽然云资源位于第三方云服务商的数据中心,但客户拥有独享的物理服务器和网络资源。
(2)高度安全性和隔离性:相比于公有云,专有云具有更高的安全性,因为物理资源不与其他客户共享。
(3)管理简化:由云服务商负责维护硬件基础设施,客户只需管理其应用和数据。
多云:
一个含有多个云环境(公共云或私有云)的IT系统,云与云之间可能联网也可能不联网。
多云是一种云架构,由多个云供应商提供的多个云服务组合而成,既可以是公共云,也可以是私有云。
参考链接:
https://www.redhat.com/zh/topics/cloud-computing/what-is-public-cloud
https://www.redhat.com/zh/topics/cloud-computing/what-is-private-cloud
https://www.redhat.com/zh/topics/cloud-computing/what-is-hybrid-cloud
https://www.redhat.com/zh/topics/cloud-computing/what-is-multicloud
云计算的服务类型
在没有云计算服务之前,如果您是运维工程师,或者公司要成立信息化部门,需要您管理以下几种环境:
网络(Networking):
相互连接的网络组件可实现内部和外部系统之间的网络操作、管理和通信。网络由互联网连接、网络支持、防火墙与安全防护,以及路由器、交换机和电缆等硬件组成。
存储(Storage):
解决公司数据的存储,比如是否考虑使用NAS类的存储设备。
服务器(Servers):
服务器的选型,包括品牌,硬件配置等。
虚拟化技术(Virtualization):
为了节省成本,您可能考虑使用虚拟化技术,将一台服务器虚拟出多台服务器来使用。
操作系统(Operating System):
需要您选择合适的操作系统,比如目前主流的Unix,Linux,Windows三大派系的选型。
中间件(Middleware):
需要您考虑是否要使用中间件服务,比如数据库服务,消息队列服务等。
运行环境(Runtime):
需要考虑是否要部署好相应的运行环境,比如Java,Python,Golang,Perl,PHP编程语言开发的运行时环境可能各有不同,这些都需要您来负责处理。
数据(Data):
要考虑数据的处理,比如随着时间的推移,本地磁盘空间使用快占满时应该及时处理这些数据的存储,处理,以及迁移等问题。
应用程序(Applications):
这就是针对应用程序的维护,比如大数据平台运维,Web集群运维,数据库运维,容器运维等。
综上所述,发现如果让我们自己来维护以上所有内容,可能会耗费相当多的人力,财力,物力。为了给企业节省上面提到的成本,衍生了云计算服务类型,大致分为以下三种:
基础设施即服务(英文名称为:"Infrastructure-as-a-Service",下面简称"IaaS"):
IaaS表示将由云服务提供商通过互联网连接为您管理基础架构,包括实际的服务器、网络、虚拟化和数据存储。用户可通过 API 或控制面板进行访问,并且基本上是租用基础架构。
诸如操作系统、应用和中间件等内容由用户管理,而提供商则负责硬件、网络、硬盘驱动器、数据存储和服务器,并负责处理中断、维修及硬件问题。这是云存储提供商的典型部署模式。
平台即服务(英文名称为:"Platform-as-a-Service",下面简称"PaaS"):
PaaS表示硬件和应用软件平台将由外部云服务提供商来提供和管理,而用户将负责平台上运行的应用以及应用所依赖的数据。
PaaS主要面向开发人员和编程人员,旨在为用户提供一个共享的云平台,用于进行应用的开发和管理(DevOps 的一个重要组成部分),而无需构建和维护通常与该流程相关联的基础架构。
软件即服务(英文名称为:"Software-as-a-Service",下面简称"SaaS"):
SaaS是将云服务提供商管理的软件应用交付给用户的服务。通常,SaaS应用是一些用户可通过网页浏览器访问的Web应用或移动应用。
该服务会为用户完成软件更新、错误修复及其他常规软件维护工作,而用户将通过控制面板或 API 连接至云应用。此外,SaaS还消除了在每个用户计算机上本地安装应用的必要性,从而使群组或团队可使用更多方法来访问软件。
参考链接:
https://www.redhat.com/zh/topics/cloud-computing/what-is-it-infrastructure
https://www.redhat.com/zh/topics/cloud-computing/what-is-iaas
https://www.redhat.com/zh/topics/cloud-computing/what-is-paas
https://www.redhat.com/zh/topics/cloud-computing/what-is-saas
docker底层原理⭐⭐⭐
2007年前后,Linux内核支持Cgroup和NameSpace技术,这两种技术在增加对Linux的整体控制的同时,也成为了保持环境隔离的重要框架。
namespace
NameSpace(命名空间)主要包含以下六种技术:
MNT Namespace(提供磁盘挂载点和文件系统的隔离能力):
每个容器都要有独立的根文件系统用户空间,以实现在容器里面启动服务并且使用容器的运行环境。换句话说,就是在容器里面不能访问宿主机的资源,宿主机是使用了chroot技术把容器锁定到一个指的运行目录里面。
举个例子:
一个宿主机是ubuntu的服务器,可以在里面启动一个centos运行环境的容器并且在里面启动一个Nginx服务,此Nginx运行时使用的运行环境就是centos系统目录的运行环境。
IPC Namespace(提供进程间通信的隔离能力):
一个容器内的进程间通信,允许一个容器内的不同进程的(内存,缓存等)数据访问,但是不能跨容器访问其他容器的数据 。
UTS Namespace(提供主机名隔离能力):
用于系统标识,其中包含了hostname和域名domainname,它使得一个容器拥有属于自己hostname标识,这个主机名标识独立于宿主机系统和其上的他容器 。
PID Namespace(提供进程隔离能力):
CentOS Linux系统中,有一个PID为1的进程(init/systemd)是其他所有进程的父。
在每个容器内也要有一个父进程来管理其下属的子进程,多个容器进程的PID namespace进程隔离(比如PID编号重复、容器内的主进程与回收子进程等)。
Net Namespace(提供网络隔离能力):
每一个容器都类似于虚拟机一样有自己的网卡,监听端口,TCP/IP协议栈等。
以Docker为例,使用network namespace启动一个vethX接口,这样你的容器将拥有它自己的桥接ip地址,通常是docker0。
上面提到的docker0本质上是Linux的虚拟网桥(Virtual Bridge),网桥是在OSI七层模型的数据链路网络设备,通过mac地址对网络进行划分,并且在不同网络直接传递数据。
User Namespace(提供用户隔离能力):
各个容器内可能会出现重名的用户和用户组名称,或重复的用户UID或者GID,那么怎隔离各个容器内的用户空间呢?
User Namespace允许在各个宿主机的各个容器空间内创建相同的用户名以及相同的用户UID和GID,只是会用户的作用范围限制在每个容器内。
即A容器和B容器可以有相同的用户名称和ID的账户,但是此用户的有效范围仅是当前容器内,不能访问另外一个容器内的文件系统,即相互隔离,互不影响,永不相见。
cgroup
Cgroups:
一个容器如果不对其做任何资源限制,则宿主机(也称为物理机,英文名称为:"Physical machine")会允许其占用无限大的内存空间,有时候会因为代码bug程序会一直申请内存,直到把宿主机内存占完。
综上所述,为了避免此类的问题出现,宿主机有必要对容器进行资源分配限制,比如CPU,内存,磁盘等。
Linux Cgroups的全称是Linux Control Groups,它最主要的作用就是限制一个进程组能够使用的资源上限,包括CPU,内存,磁盘,网络带宽等等。
此外,Linux Cgroups还能够对进程优先级设置,以及将进程挂起和恢复等操作。
docker架构
docker安装
流程:
1、安装docker所需要的一些依赖
2、下载docker软件的第三方源
3、修改为清华源
4、下载docker,启动
(梯子。。。)
5、配置镜像仓库
6、安装docker命令的自动补全工具
- 安装docker服务端docker-ce
#1.安装相关依赖.
yum install -y yum-utils device-mapper-persistent-data lvm2
#2.下载官方的docker yum源文件
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# 或者
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
cat /etc/yum.repos.d/docker-ce.repo
#如果不行用下面两条命令
#cd /etc/yum.repos.d
#wget https://download.docker.com/linux/centos/docker-ce.repo
#3.替换yum源地址
sed -i 's+download.docker.com+mirrors.tuna.tsinghua.edu.cn/docker-ce+' /etc/yum.repos.d/docker-ce.repo
#4.安装docker-ce
yum install -y docker-ce
systemctl enable --now docker
docker version # 检查
- 修改镜像仓库
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://pedh2gdb.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
- 安装docker命令自动补全工具
yum install -y bash-completion bash-completion-extras
容器vs虚拟机(面试题)
对比项 | 容器 | 虚拟机 |
---|---|---|
轻量级 | 容器共享宿主机操作系统的内核,因此每个容器只包含应用程序及其依赖项。启动和运行速度快,占用资源少 | 每个虚拟机都需要运行一个完整的操作系统内核,启动和运行时资源开销较大,性能效率低于容器 |
启动时间 | 几秒钟 | 几分钟 |
安全性 | 由于容器共享同一个操作系统内核,安全性隔离比虚拟机弱 | 虚拟机在硬件层面上提供了更强的隔离性,每个虚拟机都有自己的操作系统内核,安全性高 |
能够让开发人员的本地环境和生产环境一致 |
镜像管理
案例1:下载镜像
[root@docker01 ~]# docker pull nginx
[root@docker01 ~]# docker pull nginx:alpine
[root@docker01 ~]# docker pull nginx:1.18.0-alpine
案例2:查看镜像
[root@docker01 ~]# docker images
[root@docker01 ~]# docker images ls
[root@docker02 ~]# docker images -a
案例3:搜索镜像
[root@docker01 ~]# docker search nginx
# 一般去hub.docker.com搜索镜像
案例4:sl大法(save/load)
[root@docker01 ~]# docker image save nginx:alpine -o nginx_alpine.tar
[root@docker01 ~]# scp nginx_alpine.tar root@172.16.1.82:~/
[root@docker02 ~]# docker load -i nginx_alpine.tar
# 批量
[root@docker01 ~]# docker images |awk 'NR>1{print "docker save",$1":"$2,"-o",$1"_"$2".tar"}'
[root@docker01 ~]# scp *.tar root@172.16.1.82:~/
[root@docker02 ~]# ls *.tar | xargs -I{} docker image load -i {}
案例5:修改镜像tag
[root@docker02 ~]# docker tag nginx:alpine nginx:alpine-lyun
案例6:查看镜像信息
[root@docker02 ~]# docker image inspect nginx:alpine
容器管理
案例1:拉取镜像并直接运行为容器
[root@docker01 ~]# docker run -d -p 80:80 --name "first_docker_nginx" nginx:alpine
[root@docker01 ~]# docker run -d -p 80:80 --name "apache_container" httpd:alpine
docker run
-e key=value
案例2:查看有哪些运行中的容器
[root@docker01 ~]# docker container ps
[root@docker01 ~]# docker container ps -a
[root@docker01 ~]# docker ps -a
[root@docker01 ~]# docker ps -aq
# -a 查看所有状态的容器
# -q 查看容器的id号
# 删除所有容器:
[root@docker01 ~]# docker rm -f `docker ps -aq`
案例3:创建容器并进入容器
[root@docker01 ~]# docker run -it --name "ubuntu_18.04_container" ubuntu:18.04
root@57422f0d5020:/# du -sh /
67M /
root@57422f0d5020:/# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 13:14 pts/0 00:00:00 bash
root 13 1 0 13:14 pts/0 00:00:00 ps -ef
root@57422f0d5020:/# exit
exit
# -i 进入交互模式
# -t 分配一个终端(运行命令解释器)
# 这种方式进入容器,退出容器则容器结束
容器注意事项:
容器想要放在后台一直运行,就必须阻塞住(夯住)。
体会下面两个命令的区别:
docker run -d name "centos_v2" centos
docker run -d name "centos_v3" centos sleep 20如果想要在后台一直运行一个纯净的系统容器,就要指定一个后台一直运行的进程,例如/bin/bash
docker run -itd --name "debian_container_v1" /bin/bash
2024.8.23更正:不一定要有一个前台阻塞的进程,有标准输入即可
docker run -id --name "ubuntu_container_v1" ubuntu:18.04
-i:保持标准输入(STDIN)打开,即使没有附加终端
-d:后台运行容器
[root@docker01 ~]# docker run -itd --name ubuntu_container_v3 ubuntu:18.04 /bin/bash e89915ef578d0f8b2d096c2b528ae63a49e206f133b20cea431ec145abadee9b [root@docker01 ~]# docker exec -it ubuntu_container_v3 /bin/bash root@e89915ef578d:/# ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 03:42 pts/0 00:00:00 /bin/bash # <=====后台运行的/bin/bash,保证容器不会停止 root 11 0 0 03:43 pts/1 00:00:00 /bin/bash # <=====通过exec -it分配的前台运行的/bin/bash root 20 11 0 03:43 pts/1 00:00:00 ps -ef
docker run -it --name "debian_container_v1" /bin/bash
进入了容器的bash,相当于前台运行/bin/bash,也算有一个服务在运行,一旦退出容器,意味着/bin/bash就退出了,容器也就退出
案例4:进入已经运行中的容器
[root@docker01 ~]# docker exec -it nginx_alpine_container /bin/bash
# 没有bash就用sh
[root@docker01 ~]# docker exec -it nginx_alpine_container /bin/sh
# 进入容器并运行命令
[root@docker01 ~]# docker exec -it nginx_alpine_container mysql -uroot -p
[root@docker01 ~]# docker exec -it nginx_alpine_container redis-cli
# 拓展:如何后台持续运行纯净的系统:指定-itd+命令解释器持续运行
[root@docker01 ~]# docker run -itd --name ubuntu_container_v3 ubuntu:18.04 /bin/bash
案例5:exec与attach的区别
exec | attach | |
---|---|---|
共同点 | 连接到容器 | 连接到容器 |
区别1 | 连接的时候创建终端 | 容器中要有终端进程(容器的进程中要有/bin/bash或/bin/sh),只能连到已有的终端中 |
区别2 | 不同的exec连接互不影响 | 所有的连接都一样,甚至可以看到别人在操作什么 |
案例6:docker run vs docker create,start,stop,restart
docker run命令背后做的所有事:
docker pull
docker create
docker start
docker stop # 本质是向容器PID=1的进程发送一个kill的信号,返回码为0
docker kill -s 9 # 强制退出,返回码为非0
docker restart # 用于重启容器
重启容器中的服务有两种方式:
(1)进入容器重启服务 (2) 直接重启容器
[root@docker01 ~]# docker pull debian
[root@docker01 ~]# docker create debian:latest
d6e44415f1f5715462813a6c58aad72e7b913844c47c08c90764b205e3601577
[root@docker01 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d6e44415f1f5 debian:latest "bash" 2 seconds ago Created focused_sutherland
[root@docker01 ~]# docker start focused_sutherland
[root@docker01 ~]# docker stop focused_sutherland
[root@docker01 ~]# docker restart focused_sutherland
案例7:宿主机与容器互传文件
动作 | 命令 |
---|---|
宿主机----->容器(推) | docker cp 宿主机 容器:目录 |
容器----->宿主机(拉) | docker cp 容器:目录 容器 |
[root@docker01 code]# docker container cp index.html nginx_container_v1:/usr/share/nginx/html/
Successfully copied 4.1kB to nginx_container_v1:/usr/share/nginx/html/
# 可以加-a参数,保持属性传输
案例8:查看容器相关信息和状态stats/top/inspect
- stats:查看容器占用cpu、内存、磁盘、有几个进程等。压测容器时用得到哟!
- top:查看容器中的进程对应宿主机的PID
容器中运行的一个进程实际对应宿主机的一个进程
- inspect:查看容器信息,例如ip地址、容器名、重启策略、是否为特权容器等
[root@docker01 code]# docker container stats
[root@docker01 code]# docker stats
[root@docker01 code]# docker top nginx_container_v1
UID PID PPID C STIME TTY TIME CMD
root 9403 9380 0 14:42 ? 00:00:00 nginx: master process nginx -g daemon off;
101 9449 9403 0 14:42 ? 00:00:00 nginx: worker process
[root@docker01 code]# pstree -p
systemd(1)─┬─NetworkManager(666)─┬─{NetworkManager}(695)
│ └─{NetworkManager}(699)
├─agetty(684)
├─containerd(1258)─┬─{containerd}(1259)
│ ├─{containerd}(1260)
│ ├─{containerd}(1261)
│ ├─{containerd}(1262)
│ ├─{containerd}(1263)
│ ├─{containerd}(1264)
│ ├─{containerd}(1728)
│ ├─{containerd}(9083)
│ └─{containerd}(9089)
├─containerd-shim(9380)─┬─nginx(9403)───nginx(9449) # <===========
│ ├─{containerd-shim}(9382)
│ ├─{containerd-shim}(9383)
│ ├─{containerd-shim}(9384)
│ ├─{containerd-shim}(9385)
│ ├─{containerd-shim}(9386)
│ ├─{containerd-shim}(9387)
│ ├─{containerd-shim}(9388)
│ ├─{containerd-shim}(9389)
│ ├─{containerd-shim}(9390)
│ ├─{containerd-shim}(9391)
│ └─{containerd-shim}(9392)
├─crond(676)
[root@docker01 code]# docker inspect nginx_container_v1 | jq .[].Name
案例9:结束容器
- stop 退出返回值为0,正常退出
- rm -f ,如果想要删除运行中的容器,就要加-f参数
- kill -s 9 (类似kill -9) 退出返回值为非0,非正常退出
[root@docker01 code]# docker stop nginx_container_v1
[root@docker01 code]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f7eab601564b nginx:alpine "/docker-entrypoint.…" 6 minutes ago Exited (0) 4 seconds ago nginx_container_v1
[root@docker01 code]# docker kill -9 nginx_container_v1
[root@docker01 code]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f7eab601564b nginx:alpine "/docker-entrypoint.…" 7 minutes ago Exited (137) 8 seconds ago nginx_container_v1
[root@docker01 code]# docker rm nginx_container_v1
Error response from daemon: cannot remove container "/nginx_container_v1": container is running: stop the container before removing or force remove
[root@docker01 code]# docker rm -f nginx_container_v1
nginx_container_v1
案例10:commit自定义镜像
需求:自定义一个游戏镜像
流程:
1、运行nginx容器并进入
2、编写nginx配置文件,上传网站源码
3、外部访问测试
4、运行docker commit,将容器保存为镜像
5、后续可以导出镜像给其他用户使用
[root@docker01 code]# docker run -d -p 80:80 --name "nginx_restart_game_v1" nginx:alpine
[root@docker01 code]# docker exec -it nginx_restart_game_v1 /bin/sh
/ # cat /etc/nginx/conf.d/default.conf
server {
listen 80;
server_name game.etiantian.org;
root /app/code
location / {
index index.html index.htm;
}
}
/ # mkdir -p /app/code
/ # cd /app/code/
/app/code # unzip game.zip && rm -f game.zip
/app/code # mv game/html5/* . && rm -rf html5
/app/code # nginx -t
/app/code # nginx -s reload
新开的一个窗口做的事:
# 将游戏源码传到容器站点目录
[root@docker01 code]# docker cp game.zip nginx_restart_game_v1:/app/code
[root@docker01 ~]# docker commit nginx_restart_game_v1 nginx:html_game_v1
[root@docker01 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx html_game_v1 dfda69f46139 5 seconds ago 50.5MB
[root@docker01 ~]# docker image save nginx:html_game_v1 -o html_game.tar
# 后续可以在其他机器上导入。。。。。
案例11:容器自启动--restart
默认情况下,重启docker后所有容器全部删除
2024.9.26补充说明三种重启策略的区别
restart的策略:
- always:无论容器是正常退出还是崩溃,Docker 都会自动重启该容器。如果你手动停止了容器,它会在 Docker 服务重启后再次自动启动(手动停止的容器会在 Docker 服务重启后自动重新拉起)
- unless-stopped:如果容器崩溃,它会被自动重启;如果你手动停止了容器,它不会自动重启。但如果 Docker 服务重启,停止的容器也不会重启,除非你手动再次启动它(手动停止的容器不会在 Docker 服务重启后自动重新拉起)
- on-failure:只有当容器因为错误退出时,Docker 才会重启它,最多重启 5 次。如果容器正常退出,或者你手动停止它,则不会重启
- no:默认值,不会重启容器
[root@docker01 php]# docker run -d -p 80:80 --name "nginx_alpine_container" --restart=always nginx:alpine
案例12:容器退出自动删除--rm
测试的时候可以使用
[root@docker01 ~]# docker run -it --name "ubuntu_container" --rm ubuntu:20.04
案例13:查看最后运行的一个容器-l
docker ps -l
案例14:查看容器日志
# 实时查看容器日志
docker logs -f container_name
# 查看容器最近20分钟的日志
docker logs --since 20m container_name
案例15:查看容器全量的id
默认情况下,通过docker ps查看到的容器id是省略版,可以在/var/lib/docker下查看到容器的全量id,当然该路径也可修改~
docker ps --no-trunc
端口映射
本质是通过iptables nat规则实现的.nat表中创建了docker自定义的链
通过docker run -p实现
docker run | |
---|---|
-p选项(小写字母P) 宿主机端口:容器中的端口 | -p 80:80 -p 443:443 |
-p :容器中端口 | -p :80 表示宿主机端口随机,很少用. |
-p 端口范围:端口范围 | 80-88:80-88 |
用户访问docker容器中的服务的全流程
案例:查看容器端口映射
[root@docker01 ~]# docker port mulport_container_v1
案例:1对1端口映射
[root@docker01 ~]# docker run -d -p 80:80 -p 81:81 -p 82:83 --name "mulport_container_v1" nginx:alpine
案例:映射多个端口
[root@docker01 ~]# docker run -d -p 8083-8085:8080-8082 --name "mulport_container_v2" nginx:alpine
案例:ip绑定端口
用于安全性保护
[root@docker01 ~]# docker run -d -p 172.16.1.81:1000:80 --name "ip_binding_port_container_v1" nginx:alpine
# 此时浏览器就无法访问到容器内的nginx
数据卷挂载
-
不使用数据卷,使用rm删除容器时,容器内所有数据都会丢失
-
如何解决数据持久化问题?-> 数据卷,让容器中的数据保存到宿主机中
-
使用:-v 宿主机目录/文件:容器目录/文件
案例1:将宿主机中的web目录挂载到容器中的web目录
达到的效果:修改宿主机中的网页代码就可以直接影响到容器中的网页代码
核心命令:
[root@docker01 ~]# docker run -d -p 80:80 --name "nginx_volumes_container_v1" -v /app/code/:/usr/share/nginx/html/ nginx:alpine
# nginx配置文件+网页源代码
docker run -d -p 80:80 --name "nginx_game_volume_v1" \
-v /app/docker/code:/usr/share/nginx/html \
-v /app/docker/conf/nginx.conf:/etc/nginx/nginx.conf \
-v /app/docker/conf/conf.d:/etc/nginx/conf.d \
nginx:alpine
注意:将目录挂载到容器中,实际上是将目录下的所有文件挂载到容器
例如/app/docker/code:/usr/share/nginx/html,就是将宿主机/app/docker/code目录下的所有文件挂载到容器中/usr/share/nginx/html目录下
共享存储挂载:
案例2:创建数据卷空间
应用场景: 只关注容器中的数据不丢,不关注数据具体放在哪里.
将nginx容器中/etc目录保存到宿主机中
流程:
1、创建数据卷空间
2、创建容器时指定数据卷空间
[root@docker01 ~]# docker volume create confdata
[root@docker01 ~]# docker volume ls
DRIVER VOLUME NAME
local confdata
[root@docker01 ~]# docker run -d -p 81:80 --name "nginx_volume_v2" -v confdata:/etc nginx:alpine
8e25d28172c826a74816ee3ac73d8540b099e393a1f93b235d04cad2577b0af3
[root@docker01 ~]# ls /var/lib/docker/volumes/
backingFsBlockDev confdata metadata.db
[root@docker01 ~]# ls /var/lib/docker/volumes/confdata/_data/
alpine-release conf.d group- inittab modules network passwd profile.d services ssl terminfo
apk crontabs hostname issue modules-load.d nginx passwd- protocols shadow ssl1.1 udhcpd.conf
ca-certificates fstab hosts logrotate.d motd opt periodic resolv.conf shadow- sysctl.conf
ca-certificates.conf group init.d modprobe.d mtab os-release profile securetty shells sysctl.d
案例3:删除存储卷
删除容器,顺带删除容器关联的匿名存储卷
docker rm -fv <container_name_or_id>
-- 这种方式不会删除命名卷!!!删除命名卷需要单独docker volume rm
删除命名存储卷
docker volume rm
Dockerfile
以构建tengine镜像为例
先手动构建tengine镜像
全流程
1、下载并启动ubuntu:20.04 容器,name为ubuntu_tengine_test
2、配置apt源
3、上传tengine源码包、下载常用软件包、编译安装所需软件包
4、编译安装3步曲 ./configure ; make ; make install
5、启动与测试
6、清理痕迹
7、生成镜像 docker commit
[root@docker01 ~]# docker pull ubuntu:20.04
[root@docker01 ~]# docker run -itd --name "ubuntu_tengine_v1" ubuntu:20.04 /bin/bash
[root@docker01 ~]# docker exec -it ubuntu_tengine_v1 /bin/bash
# 修改apt源
root@d2afa1bd8c0f:/# sed -ri 's#archive.ubuntu.com|security.ubuntu.com#mirrors.aliyun.com#g' /etc/apt/sources.list
root@d2afa1bd8c0f:/# apt update # 更新源
root@d2afa1bd8c0f:~# apt install -y vim curl
# 外部通过docker ps上传
root@d2afa1bd8c0f:~# ls
tengine-2.3.3.tar.gz
root@d2afa1bd8c0f:~# tar xf tengine-2.3.3.tar.gz
root@d2afa1bd8c0f:~# apt install -y libssl-dev make gcc pcre2-utils libpcre3-dev zlib1g-dev
root@d2afa1bd8c0f:~# cd tengine-2.3.3
root@d2afa1bd8c0f:~/tengine-2.3.3# ./configure --prefix=/app/tools/tengine-2.3.3/ \
--user=nginx \
--group=nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_stub_status_module \
--with-http_mp4_module \
--with-stream \
--with-stream_ssl_module \
--with-stream_realip_module \
--add-module=modules/ngx_http_upstream_check_module/ \
--add-module=modules/ngx_http_upstream_session_sticky_module
root@d2afa1bd8c0f:~/tengine-2.3.3# make -j 1
root@d2afa1bd8c0f:~/tengine-2.3.3# echo $?
root@d2afa1bd8c0f:~/tengine-2.3.3# make install
root@d2afa1bd8c0f:~/tengine-2.3.3# /app/tools/tengine-2.3.3/sbin/nginx -V # 检查nginx版本
root@d2afa1bd8c0f:~/tengine-2.3.3# ln -s /app/tools/tengine-2.3.3/ /app/tools/tengine
root@d2afa1bd8c0f:~/tengine-2.3.3# ln -s /app/tools/tengine/sbin/nginx /sbin
root@d2afa1bd8c0f:~/tengine-2.3.3# groupadd nginx
root@d2afa1bd8c0f:~/tengine-2.3.3# useradd -s /sbin/nologin -g nginx nginx
root@d2afa1bd8c0f:~/tengine-2.3.3# nginx # 启动tengine
root@d2afa1bd8c0f:~/tengine-2.3.3# echo docker-tengine-damianhuang >/app/tools/tengine/html/index.html
root@d2afa1bd8c0f:~/tengine-2.3.3# curl localhost
docker-tengine-damianhuang
# 清理
root@d2afa1bd8c0f:~/tengine-2.3.3# rm -fr /tmp/*
root@d2afa1bd8c0f:~/tengine-2.3.3#
root@d2afa1bd8c0f:~/tengine-2.3.3# rm -fr /var/cache/*
[root@docker01 ~]# docker commit ubuntu_tengine_v1 tengine:2.3.3-ubuntu20.04 # 生成镜像
运行镜像
注意!!!!!
启动容器容器中,要有个服务在前台阻塞住.
这个容器中没有配置的.
需要手动指定.nginx -g 'daemon off;'
[root@docker01 ~]# docker run -d -p 80:80 --name "ubuntu_tengine_test" tengine:2.3.3-ubuntu20.04 nginx -g 'daemon off;'
浏览器访问测试。。。。
关于日志
关于日志的处理
方法①:日志目录挂载到宿主机的某个目录中
方法②:把日志软链接到/dev/stdout 和/dev/stderr中,未来可以通过docker logs 查看日志
root@584352d97e68:/app/tools/tengine/logs# ln -sf /dev/stdout /app/tools/tengine/logs/access.log
root@584352d97e68:/app/tools/tengine/logs# ln -sf /dev/stderr /app/tools/tengine/logs/error.log修改完记得重启容器 docker restart ubuntu_tengine_test
[root@docker01 ~]# docker logs -f ubuntu_tengine_test
注:docker logs -f 实时查看日志输出 -n 数字 查看最后几行的日志
dockerfile中的指令
dockerfile指令 | 含义 | 应用 | 建议 |
---|---|---|---|
dockerfile开头部分 | |||
FROM | 指定基本镜像类似于 docker pull 下载镜像 | FROM ubuntu:20.04 | 尽量少写ubuntu或ubuntu:latest,尽量指定具体的版本. |
LABEL | 用于指定容器的属性信息,作者,个人联系方式(邮件) | LABEL author="damianhuang" | 推荐使用LABEL,不推荐使用下面的MAINTAINER |
MAINTAINER | 不再使用,推荐使用LABEL 个人信息 | ||
ENV | 用于创建Dockerfile中使用的变量 | ENV Tengine_Version空格2.3.3 | 软件版本可以创建使用变量. |
dockerfile中间处理部分 | |||
RUN | 制作镜像过程中需要的执行命令,通常系统配置,服务配置,部署。但不能出现阻塞当前终端的命令。 | RUN 系统命令即可. | 不建议使用连续多个RUN,合并连续多个RUN. |
ADD | 可以把指定文件或目录拷贝到容器中(指定目录), 会解压压缩包 .相对于当前目录. | ADD restart.tar.gz空格/app/code/restart/ | 拷贝压缩包使用. |
COPY | 可以把指定文件或目录拷贝到容器中(指定目录),不支持自动解压.相对于当前目录. | COPY nginx.conf空格/etc/nginx/nginx.conf | 拷贝文件或目录. |
WORKDIR | 指定 容器 的默认工作目录. | WORKDIR /app/code/restart/ ADD restart.tar.gz空. |
一般用于配合ADD,COPY需要书写容器中路径指令. Dockerfile中使用相对路径操作容 器. |
VOLUME | 挂载数据卷. | 创建随机数据卷挂载容器的目录. 推荐docker run的时候指定 -v 即可. |
|
dockerfile结尾部分 | |||
EXPOSE | 指定镜像要对外暴露的端口 | EXPOSE 80 | 用于指定一个或多个容器的端口. 未来这个端口可以被-P识别. xxxx:80 |
CMD | 用于指定容器的入口命令.入口命令可以在docker run的时候替换.运行镜像 启动容器的时候,容器默认运行的命令是什么 |
CMD ["命令","参数01","参数02"] CMD ["nginx","-g","daemon off;"] |
大部分都会使用CMD |
ENTRYPOINT | 用于指定容器的入口命令.无法被docker run替换, dockerrun指定的时候仅 仅作为 entrypoint命令的参数而已 |
ENTRYPOINT ["executable", "param1", "param2"] |
使用不多 |
常见服务前台运行的方式:
nginx -g 'daemon off;' nginx前台运行.
/usr/sbin/php-fpm nodaemonize php前台运行.
/usr/sbin/sshd -D ssh前台运行.
java -jar xxx.jar java前台运行.
案例1:使用Dockerfile自动化构建tengine镜像
[root@docker01 tengine]# pwd
/app/dockerfile/tengine
[root@docker01 tengine]# ls
Dockerfile tengine-2.3.3.tar.gz
[root@docker01 tengine]# docker build -t "tengine:2.3.3_by_dockerfile" .
[root@docker01 tengine]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tengine 2.3.3_by_dockerfile dd89888b41e6 2 minutes ago 355MB
[root@docker01 tengine]# docker run -d -p 81:80 --name "tengine_dockerfile" tengine:2.3.3_by_dockerfile
编写dockerfile
FROM ubuntu:20.04
LABEL author="Lyun_DamianHuang" \
url="www.lyun.cn"
ADD tengine-2.3.3.tar.gz /tmp/
RUN sed -ri 's#archive.ubuntu.com|security.ubuntu.com#mirrors.aliyun.com#g' /etc/apt/sources.list \
&& apt update \
&& apt install -y libssl-dev make gcc pcre2-utils libpcre3-dev zlib1g-dev \
&& cd /tmp/tengine-2.3.3 \
&& ./configure --prefix=/app/tools/tengine-2.3.3/ \
--user=nginx \
--group=nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_stub_status_module \
--with-http_mp4_module \
--with-stream \
--with-stream_ssl_module \
--with-stream_realip_module \
--add-module=modules/ngx_http_upstream_check_module/ \
--add-module=modules/ngx_http_upstream_session_sticky_module \
&& make -j 1 \
&& make install \
&& ln -s /app/tools/tengine-2.3.3/ /app/tools/tengine \
&& ln -s /app/tools/tengine/sbin/nginx /sbin \
&& groupadd nginx \
&& useradd -s /sbin/nologin -g nginx nginx \
&& nginx \
&& echo docker-tengine-damianhuang >/app/tools/tengine/html/index.html
RUN rm -fr /tmp/* /var/cache/*
EXPOSE 80
CMD [ "nginx","-g","daemon off;" ]
案例2:使用变量
ENV指令定义变量,${}调用变量
案例3:多服务镜像nginx+php
全流程
1、纯净centos7镜像
2、准备好php+nginx软件包,安装(可以随便找一台centos安装php+nginx,然后将缓存下来的rpm包打包)
3、修改php的/etc/php-fpm.d/www.conf用户、组为nginx
4、写入口脚本/entrypoint.sh
[root@docker01 multi_service_nginx_php]# ls
Dockerfile entrypoint.sh php_nginx.tar.gz
[root@docker01 multi_service_nginx_php]# cat Dockerfile
FROM centos:centos7.9.2009
LABEL author="Lyun-DamianHuang" \
email="2929531141@qq.com" \
phone_number="18695619572"
ADD php_nginx.tar.gz /tmp/
ADD entrypoint.sh /
RUN cd /tmp/php_nginx \
&& yum localinstall *.rpm -y \
&& sed -i 's#user = apache#user = nginx#g' /etc/php-fpm.d/www.conf \
&& sed -i 's#group = apache#group = nginx#g' /etc/php-fpm.d/www.conf \
&& cd /usr/share/nginx/html/ \
&& rm -fr * \
&& echo "hello,nginx" >index.html
EXPOSE 80
CMD ["/entrypoint.sh"]
[root@docker01 multi_service_nginx_php]# cat entrypoint.sh
#!/bin/sh
php-fpm
nginx -g "daemon off;"
案例4:使用上面的镜像部署kodexplorer
全流程:
1、将案例3的整个dockerfile文件夹复制一份过来
2、添加网站源代码、nginx主配置文件、nginx子配置文件
3、基于案例3生成的镜像,再写一份dockerfile,生成应用镜像
[root@docker01 kodexp_based_multi]# ls
code conf Dockerfile entrypoint.sh php_nginx.tar.gz
[root@docker01 kodexp_based_multi]# ls code
kodexp.tar.gz # <=========经过处理多一层kodexp目录,这样上传到容器后自动解压就带一层目录
[root@docker01 kodexp_based_multi]# ls conf
kodexp.etiantian.org.conf nginx.conf
- 主配置文件
#主配置文件
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
# tcp_nopush on;
keepalive_timeout 65;
# gzip on;
include /etc/nginx/conf.d/*.conf;
}
- 子配置文件
# 子配置文件
server {
listen 80;
server_name kodexp.etiantian.org;
root /app/code/kodexp;
location / {
index index.php;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME
$document_root$fastcgi_script_name;
include fastcgi_params;
}
}
- 网站源代码多一层目录处理
[root@docker01 code]# mkdir kodexp
[root@docker01 code]# unzip -q kodbox.1.37.zip -d kodexp/
[root@docker01 code]# ls
kodbox.1.37.zip kodexp
[root@docker01 code]# rm -f kodbox.1.37.zip
[root@docker01 code]# tar -zcf kodexp.tar.gz kodexp/
[root@docker01 code]# ls
kodexp kodexp.tar.gz
[root@docker01 code]# rm -fr kodexp
- dockerfile编写(基于上面案例3生成的php+nginx镜像)
[root@docker01 kodexp_based_multi]# cat Dockerfile
FROM web:multi_service
COPY conf/nginx.conf /etc/nginx/nginx.conf
COPY conf/kodexp.etiantian.org.conf /etc/nginx/conf.d/kodexp.etiantian.org.conf
ADD code/kodexp.tar.gz /app/code
# 这两步似乎不需要?
# EXPOSE 80
# ["/entrypoint.sh"]
案例5:多阶段提交⭐⭐
应用场景:
- 压缩镜像的大小
- 适用于编译安装/构建场合,先通过中间镜像进行编译,再将编译结果存放到新的镜像中
全流程
1、创建镜像的时候起个别名 FROM xxx AS temp
2、对中间镜像进行操作,下载依赖,下载软件包,编译....
3、创建镜像 FROM ubuntu:20.04
4、把中间镜像的命令,配置文件/目录复制到最终镜像中.
5、复制代码
6、EXPOSE 80, 设置入口指令CMD....FROM xxx AS yyy
ADD --from=xxx src dest
[root@docker01 multi_stage]# ls
Dockerfile html.tar.gz tengine-2.3.3.tar.gz
dockerfile
[root@docker01 multi_stage]# cat Dockerfile
#1. 基本信息
FROM ubuntu:20.04 AS TEMP
LABEL author="lidao996" \
url="www.oldboyedu.com"
#2. vars
ENV WEB_SERVER=tengine-2.3.3
ENV INSTALL_DIR=/app/tools/${WEB_SERVER}
ENV NGX_USER=nginx
ENV CPU_CORES=1
#2. 传输软件包
ADD tengine-2.3.3.tar.gz /tmp/
#3. 环境准备
RUN sed -ri 's#archive.ubuntu.com|security.ubuntu.com#mirrors.aliyun.com#g' /etc/apt/sources.list \
&& apt update \
&& apt install -y libssl-dev make gcc pcre2-utils libpcre3-dev zlib1g-dev \
&& cd /tmp/tengine-2.3.3/ \
&& ./configure --prefix=${INSTALL_DIR} \
--user=${NGX_USER} \
--group=${NGX_USER} \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_stub_status_module \
--with-http_mp4_module \
--with-stream \
--with-stream_ssl_module \
--with-stream_realip_module \
--add-module=modules/ngx_http_upstream_check_module/ \
--add-module=modules/ngx_http_upstream_session_sticky_module \
&& make -j ${CPU_CORES} \
&& make install
#编译安装结束生成命令 源码目录/tmp/tengine-2.3.3/objs/nginx
# 下面待整理, 创建软连接,添加用户
# 到此为止第1个镜像的任务已经完成了.
#
FROM ubuntu:20.04
ENV NGX_USER=nginx
COPY --from=TEMP /app/ /app/
RUN sed -ri 's#archive.ubuntu.com|security.ubuntu.com#mirrors.aliyun.com#g' /etc/apt/sources.list \
&& apt-get update
RUN apt-get install -y libssl-dev pcre2-utils libpcre3-dev zlib1g-dev
RUN ln -s /app/tools/tengine-2.3.3/ /app/tools/tengine \
&& ln -s /app/tools/tengine/sbin/nginx /sbin/nginx \
&& useradd -s /sbin/nologin ${NGX_USER}
#ADD game.tar.gz /app/tools/tengine/html/
ADD html.tar.gz /app/tools/tengine/
RUN rm -fr /tmp /var/cache
# 设置暴露80端口和入口指令
EXPOSE 80
CMD [ "nginx","-g","daemon off;" ]
dockerfile小结
- 熟练掌握dockerfile格式及书写、dockerfile常用的指令.
- 尽量多阅读官方或gitee/github上面的代码中的dockerfile.老男孩教育-王牌VIP班
- 生产环境相关建议:
生产环境应用建议 | 说明 |
---|---|
尽量保证每个镜像功能单一 | 尽量避免多个服务运行在同一个镜像中 |
选择合适的基础镜像 | 不一定都要从头做(系统,ngx,tengine,tomcat,jdk) |
注释与说明 | 添加一定的注释和镜像属性信息(LABEL) |
指定版本号 | 使用镜像的时候指定版本,nginx:latest php:latest nginx:1.20.2-alpine |
减少镜像层数/步骤 | 尽可能合并RUN,ADD,COPY |
记得收尾 | 清理垃圾,记得清理缓存,临时文件,压缩包.... |
合理使用.dockerignore | 构建的忽略的文件(了解),少传输些文件. |
镜像层次结构
容器互联--link
案例:分离式nginx+php
--link 容器名字:别名
别名可以在nginx转发给php程序的时候使用
- nginx:1.22.1-alpine
- php:7-fpm #php:7-fpm-alpine /usr/local/etc/php-
fpm.d/www.conf - 修改配置,挂载配置
- 挂载代码
[root@docker01 kodexp]# tree -L 2
.
├── code
│ ├── app
│ ├── ChangeLog.md
│ ├── config
│ ├── data
│ ├── index.php
│ ├── plugins
│ ├── README.MD
│ └── static
└── conf
├── kodexp.conf
├── nginx.conf
└── www.conf
docker run -d --name "kodexp_php" \
-v `pwd`/conf/www.conf:/usr/local/etc/php-fpm.d/www.conf \
-v `pwd`/code:/app/code/kodexp \
php:7-fpm
[root@docker01 conf]# cat www.conf
[www]
user = www-data
group = www-data
listen = 0.0.0.0:9000
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
# --link
docker run -d --name "kodexp_nginx" -p 10086:80 \
--link kodexp_php:php \
-v `pwd`/conf/nginx.conf:/etc/nginx/nginx.conf \
-v `pwd`/conf/kodexp.conf:/etc/nginx/conf.d/kodexp.conf \
-v `pwd`/code:/app/code/kodexp/ \
nginx:alpine
[root@docker01 conf]# cat kodexp.conf
server {
listen 80;
server_name kodexp.etiantian.org;
root /app/code/kodexp;
location / {
index index.php;
}
location ~ \.php$ {
fastcgi_pass php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME
$document_root$fastcgi_script_name;
include fastcgi_params;
}
}
[root@docker01 conf]# cat nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
# tcp_nopush on;
keepalive_timeout 65;
# gzip on;
include /etc/nginx/conf.d/*.conf;
}
chown -R 777 code
docker网络
概述
Docker 提供了几种默认的网络类型,分别适用于不同的场景:
- Bridge 网络(默认网络):
- 这是 Docker 容器的默认网络模式。每个容器都会连接到一个虚拟网桥(默认是
docker0
),容器之间通过桥接网络进行通信。容器可以使用虚拟网络接口(通常是eth0
)与其他容器或宿主机通信。 - 使用
bridge
网络时,容器可以通过其 IP 地址或容器名称进行互相访问。 - 适用于单机容器间的通信场景。
- 这是 Docker 容器的默认网络模式。每个容器都会连接到一个虚拟网桥(默认是
- Host 网络:
- 容器共享宿主机的网络栈,直接使用宿主机的 IP 地址。这样,容器不再有独立的 IP 地址,而是共享宿主机的网络。
- 性能更高,因为不需要通过虚拟网络接口转发数据,但容器之间不隔离网络,容易导致端口冲突。
- 适合高性能需求的场景,如需要低延迟的服务。
- None 网络:
- 容器不连接任何网络。容器启动后,只有一个回环接口
lo
,这意味着该容器与其他容器、宿主机或外部网络完全隔离。 - 通常用于对网络有严格限制的场景,或需要自定义网络配置的场合。
- 容器不连接任何网络。容器启动后,只有一个回环接口
- Overlay 网络:
- 用于跨多个宿主机的容器通信,适用于 Swarm 或 Kubernetes 集群。
overlay
网络可以将不同宿主机上的容器连接在一起,允许容器跨节点通信。 - 通过 VxLAN(虚拟扩展局域网)协议进行通信,主要用于分布式架构下的微服务部署场景。
- 通过容器的两块网卡,既解决了多节点网络通信的问题,又能让容器上网,又不需要像macvlan一样,手动分配ip地址
- 用于跨多个宿主机的容器通信,适用于 Swarm 或 Kubernetes 集群。
- Macvlan 网络:
- 容器获得一个独立的 MAC 地址,并且可以像物理设备一样连接到宿主机的网络。容器可以与宿主机上的其他物理设备在同一网络上进行通信。
- 适合需要容器和外部设备进行直接通信的场景,如需要直接暴露容器的网络服务,或者与宿主机网络无缝集成。
- 解决了不同节点间容器通信的问题,但是需要手动给容器分配ip地址,且容器不能上网
--link选项(了解)
-
启动容器时,我们可以使用"--link"选项来关联指定的容器,本质上是将关联容器的名称的机器IP地址添加到容器的"/etc/hosts"解析中。
-
使用"--link"有一个美中不足的情况,就是要求被关联的容器必须处于运行状态!否则就会抛出"Cannot link to a non running container"异常。
-
值得一提的是,"--link"参数只是单向的配置,本质上是你在某个容器的"/etc/hosts"添加了相应的解析,对其它容器的"/etc/hosts"并没有任何影响哟~
-
温馨提示:
关于"--link"的使用了解即可,如果有别人这样写你要明白啥意思,我们在生产环境中建议大家为各个服务使用自定义网络。
[root@docker01 docker]# docker run -id --name alpine alpine:latest
[root@docker01 docker]# docker run -id --link alpine:damianhuang_alpine alpine:latest
[root@docker01 docker]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cd9603fc4a9a alpine:latest "/bin/sh" 11 seconds ago Up 10 seconds hopeful_roentgen
[root@docker01 docker]# docker exec -it hopeful_roentgen sh
/ #
/ # 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.2 damianhuang_alpine 377c7d7dc9bf alpine # 被关联的容器的别名被写在了/etc/hosts中!
172.17.0.3 cd9603fc4a9a
/ #
/ # ping damianhuang_alpine
PING damianhuang_alpine (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.064 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.052 ms
64 bytes from 172.17.0.2: seq=2 ttl=64 time=0.084 ms
单节点容器网络通信
docker五种基础网络类型概述
bridge:
默认类型,桥接到宿主机docker0的网络,类似于VM的Nat模式。
host:
host类型,使用宿主机网络,网络性能最高。
container:
容器类型,使用其它容器的共享网络,这在K8S中频繁使用。比如同一个Pod中可以有多个容器共存。
none:
没有网络,该容器不能上外网。
network:
自定义网络,我们可以使用docker network create创建自定义网络。
温馨提示:
(1)从严格意义上来说docker就只有3种基础网络类型,分别为bridge,host和none;
(2)其中container和network本质上都是基于上述3种基础网络类型哟;
bridge类型
[root@docker01 ~]# docker run --name "bridge_alpine" -id --network bridge alpine
# 可以发现,bridge网络类型的容器,网卡桥接到宿主机的docker0网卡
[root@docker01 ~]# docker exec -it bridge_alpine ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02
inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:656 (656.0 B) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
[root@docker01 ~]#
[root@docker01 ~]# ifconfig docker0
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:7ff:fe7e:9cd7 prefixlen 64 scopeid 0x20<link>
ether 02:42:07:7e:9c:d7 txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 5 bytes 446 (446.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
host类型
[root@docker01 ~]# docker run -id --name "host_alpine" --network host alpine
1b290d92985c47d4047b8b0ebb8196c0b59815de3bd4858da9ff551e4ed0b351
[root@docker01 ~]#
[root@docker01 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1b290d92985c alpine "/bin/sh" 3 seconds ago Up 2 seconds host_alpine
6d05813126f8 alpine "/bin/sh" 3 minutes ago Up 3 minutes bridge_alpine
# 可以发现,host网络类型的容器,使用宿主机的网络
[root@docker01 ~]# docker exec host_alpine ifconfig
br-3596425bc8a3 Link encap:Ethernet HWaddr 02:42:D8:2F:8E:93
inet addr:172.18.0.1 Bcast:172.18.255.255 Mask:255.255.0.0
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
br-b7659c149586 Link encap:Ethernet HWaddr 02:42:60:3C:70:51
inet addr:172.19.0.1 Bcast:172.19.255.255 Mask:255.255.0.0
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
docker0 Link encap:Ethernet HWaddr 02:42:07:7E:9C:D7
inet addr:172.17.0.1 Bcast:172.17.255.255 Mask:255.255.0.0
inet6 addr: fe80::42:7ff:fe7e:9cd7/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:5 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:446 (446.0 B)
eth0 Link encap:Ethernet HWaddr 00:0C:29:D2:AD:32
inet addr:192.168.202.81 Bcast:192.168.202.255 Mask:255.255.255.0
inet6 addr: fe80::6ca5:ab42:7863:1095/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:1376 errors:0 dropped:0 overruns:0 frame:0
TX packets:976 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:102915 (100.5 KiB) TX bytes:100601 (98.2 KiB)
eth1 Link encap:Ethernet HWaddr 00:0C:29:D2:AD:3C
inet addr:172.16.1.81 Bcast:172.16.1.255 Mask:255.255.255.0
inet6 addr: fe80::5642:9e77:640d:6c1b/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:84 errors:0 dropped:0 overruns:0 frame:0
TX packets:20 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:5144 (5.0 KiB) TX bytes:1554 (1.5 KiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
veth9b62215 Link encap:Ethernet HWaddr 26:EE:6E:F3:E3:DF
inet6 addr: fe80::24ee:6eff:fef3:e3df/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:656 (656.0 B)
[root@docker01 ~]#
[root@docker01 ~]# ifconfig
br-3596425bc8a3: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.18.0.1 netmask 255.255.0.0 broadcast 172.18.255.255
ether 02:42:d8:2f:8e:93 txqueuelen 0 (Ethernet)
RX packets 84 bytes 5144 (5.0 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 20 bytes 1554 (1.5 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
br-b7659c149586: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.19.0.1 netmask 255.255.0.0 broadcast 172.19.255.255
ether 02:42:60:3c:70:51 txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 8 bytes 656 (656.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:7ff:fe7e:9cd7 prefixlen 64 scopeid 0x20<link>
ether 02:42:07:7e:9c:d7 txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 5 bytes 446 (446.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.202.81 netmask 255.255.255.0 broadcast 192.168.202.255
inet6 fe80::6ca5:ab42:7863:1095 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:d2:ad:32 txqueuelen 1000 (Ethernet)
RX packets 1407 bytes 105105 (102.6 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1007 bytes 107725 (105.2 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
eth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.1.81 netmask 255.255.255.0 broadcast 172.16.1.255
inet6 fe80::5642:9e77:640d:6c1b prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:d2:ad:3c txqueuelen 1000 (Ethernet)
RX packets 84 bytes 5144 (5.0 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 20 bytes 1554 (1.5 KiB)
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
veth9b62215: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::24ee:6eff:fef3:e3df prefixlen 64 scopeid 0x20<link>
ether 26:ee:6e:f3:e3:df txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 8 bytes 656 (656.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@docker01 ~]#
none类型
[root@docker01 ~]# docker run -id --name "none_alpine" --network none alpine
711957561cd2036faa5da472cc626951ce12072eac6361f285633ea3f62c3ba5
[root@docker01 ~]#
[root@docker01 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
711957561cd2 alpine "/bin/sh" 2 seconds ago Up 1 second none_alpine
1b290d92985c alpine "/bin/sh" About a minute ago Up About a minute host_alpine
6d05813126f8 alpine "/bin/sh" 4 minutes ago Up 4 minutes bridge_alpine
[root@docker01 ~]#
# 可以发现,none网络类型的容器,只有本地回环网卡
[root@docker01 ~]# docker exec none_alpine ifconfig
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
[root@docker01 ~]#
container类型
[root@docker01 ~]# docker run -id --name "container_network_type" --network container:bridge_alpine alpine
7d4ec0951c431af0a3149d3ca138ccaf9a4e8bdace7f22d280f45bff9bdc431b
[root@docker01 ~]#
[root@docker01 ~]#
[root@docker01 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7d4ec0951c43 alpine "/bin/sh" 3 seconds ago Up 2 seconds container_network_type
711957561cd2 alpine "/bin/sh" About a minute ago Up About a minute none_alpine
1b290d92985c alpine "/bin/sh" 3 minutes ago Up 3 minutes host_alpine
6d05813126f8 alpine "/bin/sh" 6 minutes ago Up 6 minutes bridge_alpine
[root@docker01 ~]#
# 可以发现,container网络类型的容器,与指定的容器共享网络名称空间
[root@docker01 ~]# docker exec container_network_type ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02
inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:656 (656.0 B) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
[root@docker01 ~]# docker exec bridge_alpine ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02
inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:656 (656.0 B) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
[root@docker01 ~]#
自定义网络
[root@docker01 ~]# docker network create -d bridge --gateway 172.26.1.254 --subnet 172.26.1.0/24 --ip-range 172.26.1.96/28 damianhuang_network
c06bfb55e061d3e5bdf3b27d87d4b56e783217d1b7b2e3708f8d9f92c1662b83
[root@docker01 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
638fe3e8c233 bridge bridge local
c06bfb55e061 damianhuang_network bridge local
e28eddb63ea5 host host local
f1d56b4cc05d none null local
[root@docker01 ~]#
[root@docker01 ~]#
[root@docker01 ~]# docker network inspect damianhuang_network
[
{
"Name": "damianhuang_network",
"Id": "c06bfb55e061d3e5bdf3b27d87d4b56e783217d1b7b2e3708f8d9f92c1662b83",
"Created": "2024-10-05T20:45:14.049839686+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.26.1.0/24",
"IPRange": "172.26.1.96/28",
"Gateway": "172.26.1.254"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
[root@docker01 ~]#
[root@docker01 ~]# docker run -id --name "custom_network" --network damianhuang_network alpine
404a35a51d747f5acac588b4993d63f57f1a72aed54e323e61815b8b9ebcbeb0
[root@docker01 ~]#
[root@docker01 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
404a35a51d74 alpine "/bin/sh" 2 seconds ago Up 1 second custom_network
7d4ec0951c43 alpine "/bin/sh" 5 minutes ago Up 5 minutes container_network_type
711957561cd2 alpine "/bin/sh" 7 minutes ago Up 7 minutes none_alpine
1b290d92985c alpine "/bin/sh" 9 minutes ago Up 9 minutes host_alpine
6d05813126f8 alpine "/bin/sh" 12 minutes ago Up 12 minutes bridge_alpine
[root@docker01 ~]#
[root@docker01 ~]# docker exec custom_network ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:1A:01:60
inet addr:172.26.1.96 Bcast:172.26.1.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:13 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:1102 (1.0 KiB) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
[root@docker01 ~]#
跨节点容器网络通信
小规模跨宿主机网络通信-macvlan
概述
macvlan是Linux kernel支持的新特性,支持的版本有v3.9-3.19和 4.0+,比较稳定的版本推荐 4.0+。
如下图所示,它一般是以内核模块的形式存在,我们可以通过以下方法判断当前系统是否支持。
如果第一个命令报错,或者第二个命令没有返回,说明当前系统不支持 macvlan,需要升级内核。
根据macvlan子接口之间的通信模式,macvlan有四种网络模式,分别为private,vepa,bridge,passthru。如果这些网络感兴趣的小伙伴可自行查阅相关资料,但我并不太建议大家在这里花费太多时间。
在Docker中,macvlan只是众多Docker网络模型中的一种,并且是一种跨主机的网络模型,作为一种驱动(driver)启用(使用"-d"参数指定),可惜呀,Docker macvlan只支持bridge模式。
相同macvlan网络之间的通信如下图所示。
由于macvlan网络会独占物理网卡,也就是说一张物理网卡只能创建一个macvlan网络,如果我们想创建多个macvlan网络就得用多张网卡,但主机的物理网卡是有限的,怎么办呢?
好在macvlan网络也是支持VLAN子接口的,所以,我们可以通过VLAN技术将一个网口划分出多个子网口,这样就可以基于子网口来创建 macvlan网络了。感兴趣的小伙伴可自行查阅相关资料。
实践
# (1) 分别在docker01、docker02节点创建macvlan网络
[root@docker01 ~]# docker network create -d macvlan --subnet=172.29.0.0/16 --gateway=172.29.0.254 -o parent=eth0 damianhuang_macvlan
1cb1c596c9bab5e3c0f1c16f6faac75dfa1aedadfc8e844232ca4d4e6b86c2c4
[root@docker02 ~]# docker network create -d macvlan --subnet=172.29.0.0/16 --gateway=172.29.0.254 -o parent=eth0 damianhuang_macvlan
7012c50e153fcf8337c25b0f9209169765120eae21213dd36c8835c7ad9abc2e
# (2) 分别在两个节点上创建网络类型为macvlan的容器,并测试通信~
[root@docker01 ~]# docker container run -it -d --name 01_macvlan --network damianhuang_macvlan --ip 172.29.0.201 alpine
513a33745044b5080a36c3272bace0092778c21f43d15da6a529c49d957f26b9
[root@docker02 ~]# docker container run -it -d --name 02_macvlan --network damianhuang_macvlan --ip 172.29.0.202 alpine
143c0691007317596de8452a6dff961a34af0dfc398c1490dda02a52c8f90ec4
[root@docker02 ~]# docker exec 02_macvlan ping 172.29.0.201
PING 172.29.0.201 (172.29.0.201): 56 data bytes
64 bytes from 172.29.0.201: seq=0 ttl=64 time=0.446 ms
64 bytes from 172.29.0.201: seq=1 ttl=64 time=0.525 ms
64 bytes from 172.29.0.201: seq=2 ttl=64 time=0.303 ms
大规模跨宿主机网络通信-overlay
概述
- 底层是基于vxlan技术实现的,感兴趣可了解~~~~
实践(可能过时)
简而言之,consul是类似于zookeeper,etcd一样的键值对数据库,我们用它来存储已分配的IP地址。如下图所示,我们成功的部署了2台docker环境指向了同一个consul服务。
(1)加载consul进行
[root@harbor250.oldboyedu.com ~]# docker image pull consul:latest
(2)运行容器
[root@harbor250.oldboyedu.com ~]# docker container run -it -d -p 10.0.0.101:8500:8500/tcp --restart=always consul:latest
(3)修改所有客户端的配置文件(我这里仅演示了一台,你可以根据自己的情况做相关的微调即可)
[root@docker201.oldboyedu.com ~]# vim /etc/docker/daemon.json
[root@docker201.oldboyedu.com ~]#
[root@docker201.oldboyedu.com ~]# cat /etc/docker/daemon.json
{
"registry-mirrors": ["https://tuv7rqqq.mirror.aliyuncs.com"],
# "insecure-registries": ["docker201.oldboyedu.com:5000"],
# "data-root":"/oldboyedu/docker",
"cluster-store": "consul://10.0.0.101:8500",
"cluster-advertise": "10.0.0.101:6666"
}
[root@docker201.oldboyedu.com ~]#
[root@docker201.oldboyedu.com ~]# systemctl restart docker
[root@docker201.oldboyedu.com ~]#
参数说明:
data-root:
指定docker的数据存储目录。
cluster-store:
配置的是nginx监听的地址。
cluster-advertise:
指定的是docker的宿主机注册到consul中的指定网卡中的ip,也可以写ip和端口号,端口只要没被占用就可以了。
docker network create -d overlay --subnet 172.30.0.0/16 --gateway 172.30.0.254 oldboyedu_overlay
温馨提示:
如下图所示,我们只需要在任意一个节点只需该命令即可,无需在所有节点上执行,因为凡是注册在consul服务中的所有docker实例均为同一个集群,会有它自动帮咱们同步网络哟~
(1)在docker202.yinzhengjie.com节点创建容器:
docker container run -it -d --name linux01 --network oldboyedu_ol01 oldboyedu_linux:v1
(2)在docker201.oldboyedu.com节点创建容器:
docker container run -it -d --name linux02 --network oldboyedu_ol01 alpine:latest
温馨提示:
(1)如下图所示,跨主机的两个容器是可以相互ping通啦~
(2)
overlay工作原理
docker-compose
概述
通过dockerfile,可以自动化地生成自定义镜像
目前存在的问题,启动多个容器,需要手动写命令启动。是否存在一种技术,能够一次性启动多个容器?=> docker-compose
容器编排工具
- 单机容器编排
- docker-compose
- 容器集群管理
- docker+ansible
- docker swarm
- mesos
- k8s
docker-compose需要单独安装(epel源中),yaml格式的语法
默认文件名:docker-compose.yml/yaml
极速上手docker-compose
- 安装docker-compose
yum -y install docker-compose
案例:使用容器互联的案例,编写docker-compose.yml文件,使得两个镜像能够一次性启动
编写镜像启动的命令
docker run -d --name "kodexp_php" \
-v `pwd`/conf/www.conf:/usr/local/etc/php-fpm.d/www.conf \
-v `pwd`/code:/app/code/kodexp \
php:7-fpm
docker run -d --name "kodexp_nginx" -p 10086:80 \
--link kodexp_php:php \
-v `pwd`/conf/nginx.conf:/etc/nginx/nginx.conf \
-v `pwd`/conf/kodexp.conf:/etc/nginx/conf.d/kodexp.conf \
-v `pwd`/code:/app/code/kodexp/ \
nginx:alpine
编写docker-compose
[root@docker01 kodexp_compose]# vim docker-compose.yml
version: "3.3"
services:
kodexp_php:
image: "php:7-fpm"
volumes:
- "./conf/www.conf:/usr/local/etc/php-fpm.d/www.conf"
- "./code:/app/code/kodexp"
kodexp_nginx:
image: "nginx:alpine"
links:
- "kodexp_php:php"
ports:
- "85:80"
depends_on:
- "kodexp_php"
volumes:
- "./conf/nginx.conf:/etc/nginx/nginx.conf"
- "./conf/kodexp.conf:/etc/nginx/conf.d/kodexp.conf"
- "./code:/app/code/kodexp/"
注意:links一定要写在ports前面,不然nginx容器立马退出
docker镜像仓库
仓库选型与概述
应用场景:
- 未来docker官方的镜像无法直接满足我们需求.
- 我们企业内部也要定制很多镜像.
- 而且这些镜像不想公开,都是私有的
docker镜像仓库方案 | 应用场景与特点 |
---|---|
镜像保存为压缩包 | 使用的时候,sl(save/load),仅适用于节点极少的情况.很不方便. |
registry镜像仓库 | 使用方便,适用于小型网站集群.(镜像不多,环境不复杂),命令行操作. |
harbor镜像仓库 | 企业级镜像仓库(docker,k8s)都可用,图形化页面. |
公有云的镜像服务 | 在公有云上申请个人,企业. |
registry
极速上手
# 0、registry的所有节点,包括客户端和服务端,都要配置hosts解析
172.16.1.81 docker01.etiantian.org
172.16.1.82 docker02.etiantian.org registry.etiantian.org
# 1、服务端拉registry仓库的镜像(registry仓库本身就是一个镜像)
docker pull registry
# 2、配置(允许registry服务端允许使用http)
cat >/etc/docker/daemon.json <<EOF
{
"registry-mirrors": ["https://pedh2gdb.mirror.aliyuncs.com"],
"insecure-registries": ["registry.etiantian.org:5000"]
}
EOF
# 重启
systemctl restart docker
# 3、服务端启动registry,创建数据卷空间
docker run -d --name "damianhuang_registry" -p 5000:5000 -v registry:/var/lib/registry \
--restart=always registry:latest
查看镜像仓库:http://registry.etiantian.org:5000/v2/_catalog
现在还是空的
# 4、客户端将镜像推送到服务端
# 4.1 打标签
# 4.2 推送
[root@docker01 ~]# docker tag nginx:1.18.0-alpine registry.etiantian.org:5000/webserver/nginx:1.18.0-alpine-v1
[root@docker01 ~]# docker push registry.etiantian.org:5000/webserver/nginx:1.18.0-alpine-v1
# 客户端如何拉取服务端的镜像
[root@docker01 ~]# docker pull registry.etiantian.org:5000/webserver/nginx:1.18.0-alpine-v1
仓库:
[root@docker02 repositories]# ls
database webserver
[root@docker02 repositories]# pwd
/var/lib/docker/volumes/registry/_data/docker/registry/v2/repositories
小结
- registry仓库命令行操作,没有图形化界面
- 不知道镜像名是什么,不方便
- 可以将registry仓库的启动改成docker-compose
harbor
火速上手
[root@docker02 ~]# tar xf harbor-offline-installer-v2.3.1.tgz -C /app/tools/
#目录结构
common.sh
harbor.v2.3.1.tar.gz
harbor.yml.tmpl #临时配置文件 正式配置文件 叫harbor.yml
install.sh #每次修改配置 需要执行下
LICENSE
prepare
[root@docker02 harbor]# cp harbor.yml.tmpl harbor.yml
[root@docker02 harbor]# vim harbor.yml

检查不能有80端口占用
[root@docker02 harbor]# ./install.sh
提示要安装docker-compose和docker
[root@docker02 harbor]# yum -y install docker-compose
[root@docker02 harbor]# ./install.sh
服务端、客户端都要配置hosts解析、镜像仓库允许http
{
"registry-mirrors": ["https://pedh2gdb.mirror.aliyuncs.com"],
"insecure-registries": ["harbor.etiantian.org"]
}
172.16.1.82 docker02.etiantian.org registry.etiantian.org harbor.etiantian.org

客户端推送镜像
[root@docker01 ~]# docker tag nginx:alpine harbor.etiantian.org/webserver/nginx:alpine-test
[root@docker01 ~]# docker push harbor.etiantian.org/webserver/nginx:alpine-test
拉镜像
问题解决
重启docker后,harbor仓库就停掉了(harbor本身就是使用docker-compose启动的),如何启动harbor?
使用install.sh脚本安装完harbor后,会在目录下生成一个docker-compose.yml。所以可以直接使用docker-compose方式启动
[root@docker02 harbor]# ll
总用量 618140
drwxr-xr-x 3 root root 20 7月 28 12:35 common
-rw-r--r-- 1 root root 3361 7月 19 2021 common.sh
-rw-r--r-- 1 root root 5996 7月 28 12:35 docker-compose.yml
-rw-r--r-- 1 root root 632922189 7月 19 2021 harbor.v2.3.1.tar.gz
-rw-r--r-- 1 root root 7845 7月 28 12:32 harbor.yml
-rw-r--r-- 1 root root 7840 7月 19 2021 harbor.yml.tmpl
-rwxr-xr-x 1 root root 2500 7月 19 2021 install.sh
-rw-r--r-- 1 root root 11347 7月 19 2021 LICENSE
-rwxr-xr-x 1 root root 1881 7月 19 2021 prepare
[root@docker02 harbor]# docker-compose up -d
2024.8.23更新:重启服务器后,harbor无法访问,如何解决?
进入harbor安装目录,docker-compose kill -9干掉harbor相关进程,然后再docker-compose up -d启动
还缺少的内容
3、harbor的https搭建
4、使用cadvisor监控容器指标,并用Prometheus进行监控