基本概念
容器是一种轻量级、可移植、自包含的软件打包技术,由两部分组成:应用程序、依赖环境。通过标准格式打包应用的所有代码和依赖关系,确保应用能够快速、可靠地在计算环境下运行。
当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,之下的都叫“镜像层”。所有对容器的改动,无论添加、删除、修改文件都只会发生在容器层中。只有容器层是可写的,镜像层都是只读的。
实现原理
namespace
通过kernel的命名空间,将各个容器的挂载点MNT、进程间通信IPC、内核、进程号PID、网络Net、用户User与宿主机隔离。
宿主机使用chroot技术将一个指定的运行目录作为容器的根运行环境;
同一个IPC namespace共享内存资源,不同IPC namespce隔离进程间通信资源;
UNIX Timesharing System包含了运行内核的名称、版本、底层体系结构类型等用于系统标识的信息,使hostname、domainname、内核相对独立;
进程隔离对不同容器的进程PID进行重新标号。内核为所有的PID namespace维护了一个树状结构,最顶层的是系统初始时创建的,被称为root namespace,比如每个容器下的第一个进程PID 1,拥有特权;而新创建的子进程在child namespace下。子进程看不到父进程,而父进程可以通过signal方式对子节点中的进程产生影响。
每一个容器都有自己的网卡、监听端口、TCP/IP协议栈等,docker使用 network namespace启动一个vethX接口,通常是docker0,使各个容器拥有独立的桥接IP。而docker0本质就是Linux的虚拟网桥,工作在数据链路层,通过mac地址对网络进行划分,并且在不同网络直接传递数据。
各个容器可以有相同的用户名称和ID的账户,但是此用户的有效范围仅是当前容器内。
cgroups
作用是限制一个进程组能够使用的资源上限,比如CPU,内存,磁盘,网络带宽等;
在每一个 cgroups 层级结构中,每一个节点(cgroup 结构体)可以设置对资源不同的限制权重。比如上图中 cgrp1 组中的进程可以使用60%的 cpu 时间片,而 cgrp2 组中的进程可以使用20%的 cpu 时间片。
整体架构
dockerd:常驻后台的进程,监听客户端,实际调用containerd的api接口;
Containerd:容器生命周期管理、日志管理、镜像管理、存储管理、容器网络接口及网络管理;
Containerd-shim:每启动一个容器都会起一个新的containerd-shim进程,作为容器运行载体。确保runc退出之后,容器正常运行;
Runc:容器运行时,创建和启停容器等;
安装配置
docker社区版安装:https://developer.aliyun.com/mirror/docker-ce?spm=a2c6h.13651102.0.0.666e1b113IQQe1
mkdr -p /etc/docker
vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://<your-mirror-id>.mirror.aliyuncs.com"]
}
systemctl daemon-reload
systemctl restart docker
定位占用文件系统过大的容器
docker volume ls -q | xargs -I {} sh -c 'echo "查看卷: {}"; mountpoint=$(docker volume inspect --format "{{ .Mountpoint }}" {}); du -sh $mountpoint; echo "----------------------"'
关于容器、镜像、数据卷的常用命令
systemctl start docker #启动docker
systemctl stop docker #关闭docker
systemctl restart docker #重启docker
systemctl enable docker #设置开机自启动
systemctl status docker #查看docker运行状态
systemctl status docker.service #查询Docker服务状态
docker version #查看docker版本号信息
docker info #查看docker相关信息
docker stats #检查docker守护进程是否在运行
docker run:
-it 输出容器命令行的内容 即容器的自身的程序输出在控制台 有点类似前台运行
-d 和it相反 隐藏后台运行
-p 端口映射 9000::9000 外部(宿主机)端口:镜像里面运行的端口 将宿主机9000端口映射到镜像里面的9000端口
--restart 重启方式:--restart=always 表示该容器跟随docker自启
--name 启动后的容器名称
-v 挂载容器数据卷
--network 连接到某个网络(例如:--network test_net)
--network-alias 容器的网络名称(例如:--network-alias portainer)
docker ps #显示正在运行的容器
docker ps -a #-a,--all 显示全部容器,包括已停止的(默认只显示运行中的容器)
docker run --name containerName -p 80:80 -d nginx
docker pause 容器名/容器ID #让一个运行的容器暂停
docker unpause name #让一个容器从暂停状态恢复运行
docker stop name #停止一个或多个运行的容器(杀死进程、回收内存,仅剩文件系统)
docker start name #让一个停止的容器再次运行
docker start mysql redis rabbitmq nginx #启动多个容器
docker restart name #重启一个或多个容器
#docker stop与docker kill的区别:都可以终止运行中的docker容器。类似于linux中的kill和kill -9这两个命令,docker stop与kill相似,docker kill与kill -9类似
docker kill 容器名 #杀掉一个或多个运行中的容器
docker rename 容器名 新容器名 #更换容器名
#删除容器
docker rm 容器名/容器ID #删除容器
docker rm -f CONTAINER #强制删除
docker rm -f 容器名 容器名 容器名 #删除多个容器 空格隔开要删除的容器名或容器ID
docker rm -f $(docker ps -aq) #删除全部容器
docker inspect 容器名 #获取容器更多信息
docker ps -l #最后一次运行的容器
docker port 容器名/容器ID #查看端口的映射情况
docker logs 容器名 #查看容器运行日志
docker logs -f 容器名 #持续跟踪日志
docker logs -f --tail=20 容器名 #查看末尾多少行
docker diff 容器名 #查看容器的改动
#进入容器执行命令,两种方式 docker exec 和 docker attach,推荐docker exec
docker exec -it 容器名/容器ID bash
docker attach 容器名/容器ID
#从容器退到自己服务器中(不能用ctrl+C)
exit #直接退出:未添加-d(持久化运行容器)时,执行此参数 容器会被关闭
ctrl+p+q #优雅退出:无论是否添加-d参数,执行此命令容器都不会被关闭
#设置容器开机自启动
#法一 创建容器、使用docker run命令时,添加参数--restart=always,表示该容器随docker服务启动而自动启动
docker run --name mysqlLatest -p 3307:3306 --restart=always -d mysql
#若容器已启动,希望设置开机自启动
docker update 容器名/容器ID --restart=always
docker images #查看镜像
#拉取镜像
docker pull 镜像名 #拉取最新版本的镜像
docker pull 镜像名:tag #拉取镜像,指定版本
#推送镜像到服务
docker push 镜像名
docker push 镜像名:tag
docker save -o 保存的目标文件名称 镜像名 #保存镜像为一个压缩包
docker load -i 文件名 #加载压缩包为镜像
#搜索镜像
docker search [options] TERM
#删除镜像。当前镜像没有被任何容器使用 才可以删除
docker rmi 镜像名/镜像ID #删除镜像
docker rmi -f 镜像名/镜像ID #强制删除
docker rmi -f 镜像名 镜像名 镜像名 #删除多个 其镜像ID或镜像用用空格隔开即可
docker rmi -f $(docker images -aq) #删除全部镜像,-a 意思为显示全部, -q 意思为只显示ID
docker image rm 镜像名称/镜像ID #强制删除镜像
#给镜像打标签
docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
# 挂载数据卷
docker run --name mn -v html:/root/html -p 8080:80 nginx
数据卷操作:
docker volume create volumeName #创建数据卷
docker volume ls #查看所有数据卷
docker volume inspect volumeName #查看数据卷详细信息,包括关联的宿主机目录位置
docker volume rm volumeName #删除指定数据卷
docker volume prune #删除所有未使用的数据卷
docker run的命令中通过 -v 参数挂载文件或目录到容器中:
-v volume名称:容器内目录
-v 宿主机文件:容器内文件
-v 宿主机目录:容器内目录
Docker下容器间通信
桥接网络bridge
Docker中的每个容器都会被分配一个IP地址,并且可以通过这个 IP 地址在同一个网络内的其他容器之间进行通信;
主机网络host
容器会使用宿主机的tcp/ip协议栈,共享网络命名空间,不安全;
无网络模式none
容器不配置任何网络接口,只能使用 lo 回环设备;
容器网络模式container
和已存在的一个容器共享IP、主机名和名称空间,但文件系统、进程列表、服务、端口等还是隔离的。处于这个模式下的容器会共享一个网络栈,这样两个容器之间可以高效通信;