Docker介绍

Docker是一个开源项目,让应用程序布署在软件货柜下的工作可以自动化进行,借此在Linux操作系统上,提供一个额外的软件抽象层,以及操作系统层虚拟化自动管理机制

Docker利用Linux核心中的资源分离机制(例如cgroups)及Linux核心名字空间(namespaces),来创建独立的容器(containers)。

这可以在单一Linux实体下运作,避免启动一个虚拟机造成的额外负担。

Linux核心对名字空间的支持完全隔离了工作环境中应用程序的视野,包括进程树、网络、用户ID与挂载文件系统,而核心的cgroup提供资源隔离,包括CPU、存储器、block I/O与网络。从0.9版本起,Dockers在使用抽象虚拟是经由libvirt的LXC与systemd - nspawn提供界面的基础上,开始包括libcontainer库做为以自己的方式开0始直接使用由Linux核心提供的虚拟化的设施,

Dockers是有能力打包应用程序及其虚拟容器,可以在任何Linux服务器上运行的依赖性工具,这有助于实现灵活性和便携性,应用程序在任何地方都可以运行,无论是公有云、私有云、单机等。

红帽官方文档

什么是容器

容器是一种基础工具;泛指可以容纳其他物品的工具。可以部分或者完全封闭,被用于容纳、存储、运输物品;物体可以被放置在容器中,容器可以保护内容物。

人类使用容器的历史,至少有数十万乃至百万年。例如:瓶,罐,箱,篮,桶,杯。

容器技术出现的主要目的是为了"资源隔离"。

容器技术最早出现 FreeBASE jail -----> Linux vserver

  • chroot -----> 完整的根文件系统(FHS)标准的
  • namespaces -----> UTS Mount IPC PID user network
  • cgroup -----> 资源的分配和监控

通过比较复杂的代码开发的过程,调用以上三项技术实现容器的创建 ----> 管理 ---->销毁


LXC (LinuX Container) :对于原有的常用功能进行了封装,方便我们做容器的生命周期 -----> Docker (dotcloud)

Docker是隔离环境中运行的一个进程,如果进程结束,Docker就会停止。

Docker的隔离环境,拥有自己的ip地址,系统文件,主机名,进程管理等。

程序:代码,软件,命令

进程:正在运行的程序

容器和虚拟机

开机启动流程:

  • bios(basic input output system)开机自检
  • 根据bios启动项,读取硬盘第一个扇区
  • 操作系统的引导程序:grub,uefi
  • 选择启动的操作系统:centos7
  • 加载内核,硬件驱动,完成系统的初始化
  • 启动系统第一个进程:/sbin/init(centos6),systemd(centos7)

虚拟机 容器
硬件cpu支持(vt虚拟化),模拟计算硬件,走正常的开机启动,启动时间分钟级。 不需要硬件cpu的支持,共用宿主机内核,启动容器的第一个进程,启动时间秒级。
100虚拟机 100容器
100个服务 100个服务
10宿主机 6宿主机

对比项 Docker 对比结果 虚拟化
快速创建、删除 启动应用 >> 启动Guest OS + 启动应用
交付、部署 容器镜像 == 虚拟机镜像
密度 单Node 100~1000 >> 单Node 10~100
更新管理 迭代式更新,修改Dockerfile,对增量内容进行分发,存储、传输、节点启动和恢复迅速 >> 向虚拟机推送安装、升级应用软件补丁包
稳定性 每月更新一个版本 << KVM,XEN,VMware都已经很稳定
安全性 Docker具有宿主机root权限 << 硬件隔离:Guest OS运行在非根模式
监控成熟度 还在发展过程中 << Host,Hypervisor,VM的监控工具在生产环境已使用多年
高可用性 通过业务本身的高可用性来保证 << 武器库丰富:快照,克隆,HA,动态迁移,异地容灾,异地双活
管理平台成熟度 以K8S为代表,还在快速发展过程中 << 以OpenStack,vCenter,汉柏OPV-Suite为代表,已经在生产环境使用多年

什么是docker

Docker是通过内核虚拟化技术(namespaces及cgroups、cpu、内存、磁盘io等)来提供容器的资源隔离与安全保障等。由于Docker通过操作系统层的虚拟化实现隔离,所以Docker容器在运行时,不需要类似虚拟机(VM)额外的操作系统开销,提高资源利用率。

docker是一个C/S架构的软件打包器,属于一个进程,封装成一个镜像。

Docker优缺点

Docker优势:启动快,性能高,损耗少,轻量级

  • 快速部署:可以在数秒内完成启动,短时间内可以部署成百上千个应用 ,更快速交付到线上 。

  • 高效虚拟化:不需要额外的hypervisor支持,直接基于linux实现应用虚拟化,相比虚拟机大幅提高性能和效率。开销更小:不需要启动单独的虚拟机占用硬件资源。

  • 节省开支:提高服务器利用率,降低IT支出 。资源利用率更高:一台物理机可以运行数百个容器,但是一般只能运行数十个虚拟机 。

  • 简化配置:将运行环境打包保存至容器,使用时直接启动即可。

  • 快速迁移和扩展:可跨平台运行在物理机、虚拟机、公有云等环境, 良好的兼容性可以方便将应用从A 宿主机迁移到B宿主机甚至是A平台迁移到B平台 。

Docker缺点:

  • 隔离性:各应用之间的隔离不如虚拟机彻底 。

Docker底层技术

  • namespaces:名称空间(内核3.8版本之后才有,centos6 内核2.6版本)

    用来隔离各个容器,可解决容器之间的冲突。

  • cgroups (Control Group):控制组

    控制程序对资源的占用,资源统计,优先级分配,进程控制。


Linux Namespace

Linux Namespace提供了一种内核级别隔离系统资源的方法,通过将系统的全局资源放在不同的Namespace中,来实现资源隔离的目的。不同Namespace的程序,可以享有一份独立的系统资源。目前Linux中提供了六类系统资源的隔离机制,分别是:

  • Mount: 隔离文件系统挂载点

    每个容器都要有独立的根文件系统,有独立的用户空间, 以实现在容器里启动服务,并且使用容器的运行环境。但是在容器里面不能访问宿主机的资源, 宿主机使用 chroot 技术把容器锁定到一个指定的运行目录里面 。例如:/var/lib/containerd/io.containerd.runtime.v1.linux/容器ID

  • UTS: 隔离主机名和域名信息

    UNIX Timesharing System包含了运行内核的名称、版本、底层体系结构类型等信息。用于系统标识,其中包含了hostname和域名domainname,它使得一个容器拥有属于自己hostname标识,这个主机名标识独立于宿主机系统和其上的其他容器 。

  • IPC: 隔离进程间通信

    一个容器内的进程间通信允许一个容器内的不同进程的内存、缓存等数据访问,但是不能跨容器访问其他容器的数据 。

  • PID: 隔离进程的ID

    Linux系统中,有一个PID为1的进程 init/systemd是其他所有进程的父进程,那么在每个容器内也要有一个父进程来管理其下属的子进程,那么多个容器的进程通PID namespace进程隔离(比如PID编号重复、器内的主进程生成与回收子进程等 )。

  • Network: 隔离网络资源

    每一个容器都类似于虚拟机一样有自己的网卡、 监听 端口、TCP /IP 协议栈等。Docker使用network namespace 启动一个vethX接口,这样容器将拥有它自己的桥接ip地址,通常是docker0。而docker0实质就是Linux的虚拟网桥,网桥是在OSI七层模型的数据链路层的网络设备,通过mac地址对网络进行划分,并且在不同网络直接传递数据。

  • User: 隔离用户和用户组的ID(内核3.8版本)

namespace 系统调用参数 隔离内容 内核版本
UTS CLONE_NEWUTS 主机名和域名 2.6.19
IPC CLONE_NEWIPC 信号量、消息队列和共享内存 2.6.19
PID CLONE_NEWPID 进程编号 2.6.24
Network CLONE_NEWNET 网络设备、网络栈、端口等 2.6.29
Mount CLONE_NEWNS 挂载点(文件系统) 2.4.19
User CLONE_NEWUSER 用户和用户组 3.8

Linux Control Groups

用于限制一个进程组能够使用的资源上限,包括 CPU 、内存、磁盘、网络带宽等等。此外,还能够对进程进行优先级设置,以及将进程挂起恢复等操作。

一个容器 ,如果不对其做任何资源限制,则宿主机会允许其占用无限大的内存空间,有时候会因为代码bug 程序会一直申请内存,直到把宿主机内存占完,为了避免此类的问题出现,宿主机有必要对容器进行资源分配。

cgroups 具体实现:

blkio :块设备 IO 限制。
cpu :使用调度程序为 cgroup 任务提供 cpu 的访问。
cpuacct :产生 cgroup 任务的 cpu 资源报告。
cpuset :如果是多核心的 cpu ,这个子系统会为 cgroup 任务分配单独的 cpu 和内存。
devices :允许或拒绝 cgroup 任务对设备的访问。
freezer :暂停和恢复 cgroup 任务。
memory :设置每个 cgroup 的内存限制以及产生内存资源报告。
net_cls :标记每个网络包以供 cgroup 方便使用。
ns :命名空间子系统。
perf_event :增加了对每 group 的监测跟踪的能力,可以监测属于某个特定的 group 的所有线程以及运行在特定 CPU 上的线程。

容器

容器规范OCI

Open Container Initiative 是围绕 容器格式 和 runtime 建立的开放式行业标准。

OCI由Docker和其他容器行业的领导者于2015年6月建立,目前包含两个规范:运行时规范(runtime-spec)和映像规范(image-spec)。运行时规范概述了如何运行在磁盘上解压缩的“文件系统包”。在较高级别上,OCI执行下载一个OCI映像,然后将该映像解压到 OCI runtime 文件系统包 中。此时,OCI runtime 文件系统包 将由 OCI runtime 运行。

有了这两个规范,不同的容器公司开发的容器,只要兼容这两个规范,就可以保证容器的可移植性和相互可操作性。


容器runtime

runtime 是真正运行容器的地方,为了运行不同的容器, runtime 需要和操作系统内核紧密合作相互支持 ,以便为容器提供相应的运行环境 。目前主流的三种 runtime:

  • Lxc:linux上早期的 runtime。Docker 早期就是采用 Lxc 作为runtime。

  • runc:目前 Docker 默认的 runtime。遵守OCI规范,可以兼容 lxc 。

  • rkt:Core OS开发的容器 runtime。符合OCI规范 ,可以运行Docker容器。


容器管理工具

管理工具连接 runtime与用户,对用户提供图形或命令方式操作,然后管理工具将用户操作传递给runtime执行 。

  • Lxd的管理工具是Lxc

  • Runc的管理工具是 docker engine也就是大家经常提到的Dockerdocker engine包含后台deamoncli两部分。

  • Rkt 的管理工具是rktcli


容器定义工具

容器定义工具允许用户定义容器的属性和内容,以方便容器能够被保存、共享和重建 。

Docker imagedocker容器的模板,runtime依据docker image创建容器。

Docker file是包含N个命令的文本文件,通过docker file创建出``docker image `。

ACI(App container image):与 docker image 类似。是 Core OS开发的rkt容器的镜像格式。


LXC到Docker

  • LXC,将原来需要手工编码实现的容器技术,进行了封装。实现了更加方便、快速的容器创建及管理的技术。通过固有“模板”,安装并启动容器。将远程的程序包下载到本地,安装并创建好我们需要的容器。
  • 确实,LXC已经很大程度上降低了容器管理的难度,但是依然使用一些弊端。有些时候可能需要自定制模板,以及使用LXC中自带的模板,以及大规模创建及复制依然比较麻烦。所以,很难大规模的应用。
  • 所以,出现了Docker技术。Docker是在LXC基础上,使用GoLang二次开发的封装版。

Docker组成

Docker 主机 (Host):一个物理机或虚拟机,用于运行Docker服务进程和容器。

Docker 服务端 (Server): Docker 守护进程, 运行Docker容器。

Docker 客户端 (Client):客户端使用Docker命令或其他工具调用Docker API 。

Docker 仓库 (Registry):保存镜像的仓库,类似于git或svn这样的版本控制系统。

Docker 镜像 (Images):镜像可以理解为创建实例使用的模板。

Docker 容器 (Container ): 容器是从镜像生成对外提供服务的一个或一组服务 。


docker-ce

docker版本发展:

docker 1.13版本(2013):

  • docker-ce 社区版 17.03-19.03
  • docker-ee 企业版

docker-ce安装

  1. 环境准备
主机名 配置 IP
docker01 1核2g内存 10.0.0.11
docker02 1核2g内存 10.0.0.12
  • 要求:内核 > 3.8
  • 使用Base源和epel源
curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo

  1. 下载、安装、启动、开机自启
  • 阿里云源
wget -O /etc/yum.repos.d/docker-ce.repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
  • 清华源
wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/docker-ce.repo
yum install docker-ce -y
systemctl enable docker
systemctl start docker
  1. 验证
docker version
docker info

docker 镜像加速

docker-cn加速

mkdir -p /etc/docker
tee /etc/docker/daemon.json <<-'EOF'
{ "registry-mirrors": ["https://registry.docker-cn.com"]
}
EOF

阿里云加速器

① 注册阿里云账号,专用加速器地址获得路径:

https://cr.console.aliyun.com/#/accelerator

② 添加加速器到配置文件

mkdir -p /etc/docker
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://xxxxxx.mirror.aliyuncs.com"]
}
EOF

其他镜像加速

参考文档

mkdir -p /etc/docker
tee /etc/docker/daemon.json <<-'EOF'
{ "registry-mirrors": ["https://registry.docker-cn.com","https://hub-mirror.c.163.com","https://daocloud.io"]
}
EOF

使用中科大镜像

# 拉取官方镜像
docker pull xxx/yyy:zz
# 拉取中科大镜像
docker pull docker.mirrors.ustc.edu.cn/xxx/yyy:zz
# 拉取google镜像
docker pull gcr.io/xxx/yyy:zzz
# 拉取中科大镜像
docker pull gcr.mirrors.ustc.edu.cn/xxx/yyy:zzz
# 拉取kubernetes google镜像
docker pull k8s.gcr.io/xxx:yyy
docker pull gcr.io/google-containers/xxx:yyy
# 拉取中科大镜像
docker pull gcr.mirrors.ustc.edu.cn/google-containers/xxx:yyy
# 拉取quay.io镜像
docker pull quay.io/xxx/yyy:zzz
# 拉取中科大镜像
docker pull quay.mirrors.ustc.edu.cn/xxx/yyy:zzz

docker image 镜像

镜像搜索

docker search nginx

优先选择:OFFICIAL(官方),STARS 数量多的镜像。安全

不带版本号默认 latest,也就是最新版本


镜像拉取(下载)

docker pull nginx:alpine

注意版本选择,版本请到Docker Hub查看

docker pull nginx:1.18-alpine

国内镜像源

官方镜像 docker.io/library/nginx:1.18-alpine
用户镜像 docker.io/t29617342/alpine:3.9
国内镜像 index.tenxcloud.com/system_containers/metrics-server-amd64:v0.3.1

镜像推送(上传)

docker push 镜像名

默认上传至官方仓库,需要先登录

docker login

查看镜像列表

docker images
docker image ls
# 参数解释
REPOSITORY # 镜像所属的仓库名称
TAG # 镜像版本号(标识符) 默认为 latest
IMAGE ID # 镜像唯一ID标示
CREATED # 镜像创建时间
VIRTUAL SIZE # 镜像大小

镜像导出

docker save nginx:alpine -o docker_nginx_alpine.tar.gz
docker save 3556258649b2 > ./docker_nginx_alpine.tar.gz
  • -o:指定导出镜像的位置;
  • 可以同时导出多个镜像为一个文件;
  • 指定 .tar.gz 可以导出并压缩。

镜像导入

docker load -i docker_nginx_alpine.tar.gz
docker load < docker_nginx_alpine.tar.gz

使用import导入的镜像没有仓库和标签,需要手动指定

docker import -i docker_nginx_alpine.tar.gz

镜像删除

docker rmi nginx:alpine
docker image rm 98ab35023fd6
docker rmi -f `docker image ls -q` # 强制删除所有镜像

镜像打标

docker tag 98ab35023fd6 nginx:v1

对同一个镜像可以指定多个标签,这样删除时仅删除标签。


清除无效镜像

docker image prune

比如:没有仓库和标签的镜像。


自动构建镜像

docker build --network=host -t REPOSITORY:TAG .
--network=host  # 指定构建时使用宿主机的hosts文件
-t # 指定仓库:标签

注意:容器每次启动都会挂载新生成的/etc/host文件


查看镜像构建历史

docker history nginx:latest

查看镜像或容器信息

docker inspect nginx:v1
docker inspect 98ab35023fd6
docker inspect -f "{{.NetworkSettings.IPAddress}}" f625e984b18d # 查看容器IP
docker inspect -f "{{.NetworkSettings.Gateway}}" f625e984b18d # 查看容器网关
docker inspect -f "{{.State.Pid}}" f625e984b18d # 查看容器PID号
docker inspect -f "{{.HostConfig.NetworkMode}}" f625e984b18d # 查看容器网络模式
docker inspect f625e984b18d | grep IPAddress
docker inspect f625e984b18d | grep Gateway
docker inspect f625e984b18d | grep Pid
docker inspect f625e984b18d | grep NetworkMode
docker inspect f625e984b18d | grep -A 1 Networks

nsenter

  • 安装 nsenter
yum install util-linux -y
  • 查看容器PID号
docker inspect -f "{{.State.Pid}}" f625e984b18d
  • nsenter 进入容器
nsenter -t 容器PID -m -u -i -n -p  # 根据容器PID号进入到容器中
  • 脚本:进入容器(k8s中常用)
# vim docker_in.sh
# usage: docker_in.sh CONTAINERID
# ie: docker_in.sh 14fa729e9d46
#!/bin/bash
docker_in(){
NAME_ID=$1
PID=$(docker inspect -f "{{.State.Pid}}" ${NAME_ID})
nsenter -t ${PID} -m -u -i -n -p
}
docker_in $1

docker container 容器

创建并启动容器

Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

docker run -d -p 80:80 --name="nginx" nginx:latest
docker run -it -d centos:7
docker run -it nginx:alpine /bin/sh
run                # 创建并启动一个容器
-d # 放后台运行
-p # 端口映射,将容器内服务的端口映射在宿主机的指定端口
nginx:latest # docker镜像名称
--name # 指定容器名
--network # 指定网络类型
--dns # 指定DNS
--rm # 容器停止,自动删除
--dns 223.5.5.5 # 指定容器dns
-i # 交互式访问
-t # 分配一个交换式的终端,和-d同用放后台
-e # 设置环境变量
--privileged=true # 授予此容器扩展权限,可以修改内核参数
--restart always # docker服务启动时启动容器
--link # 单向链接正在运行的容器,hosts文件中添加主机名/别名解析
-h # 指定容器的主机名
--memory 50M # 限制内存

docker run = docker create + docker start

注:容器内的第一个进程必须一直处于运行的状态,否则这个容器,就会秒退!

创建容器

docker create nginx:latest
docker create --name oldboy nginx:latest

根据镜像创建容器,没有镜像会去源下载,还没有会报错

启动容器

Usage: docker start [OPTIONS] CONTAINER [CONTAINER...]

  • -a:附加到当前终端
  • -i:交互式
docker start df06c5d211e4
docker start oldboy
docker start `docker ps -a -q` # 开启所有容器

停止容器

docker stop df06c5d211e4
docker stop oldboy
docker stop `docker ps -a -q` # 停止所有容器

重启容器

docker restart df06c5d211e4
docker restart oldboy
docker restart `docker ps -a -q` # 重启所有容器

强制停止容器

docker kill df06c5d211e4
docker kill oldboy
docker kill `docker ps -a -q` # 强制停止所有容器

查看容器列表

docker ps
docker container ls -a # -a 查看所有容器列表,默认只显示运行的容器
docker ps -a
docker ps -q                # -q 只显示IMAGE ID(sha256:64位的号码,默认只截取12位)
docker ps --no-trunc # 不截断IMAGE ID输出
docker ps -f status=exited # 查看退出的状态的容器
docker ps -l # 查看最后创建的容器

重名名容器

docker rename oldboy oldboy01

删除容器

docker rm
docker rm -f `docker ps -a -q` # 强制删除所有容器
docker rm -fv `docker ps -aq -f status=exited` # 强制删除所有退出状态的容器

清除停止容器

docker container prune

进入正在运行的容器

docker exec -it 容器id/容器名字 /bin/sh(/bin/bash)  # 分配一个新终端
docker exec -it centos:7 ls # 免交互执行命令
docker attach centos:7   # 使用同一个终端,将后台运行的终端调用到前台

容器想要放在后台一直运行,那么容器的初始命令,必须夯住(前台运行),否则容器就会退出.

nginx -g 'daemon off;'  # 指定全局选项:关闭守护进程,在前台运行
/usr/sbin/php-fpm --nodaemonize # 在前台运行
  • 退出容器:exit
  • 偷偷离开容器,容器不退出:ctrl+q,p

查看容器日志

docker logs d9e3ab321e18
-t       # 显示时间戳
-f # 跟踪日志输出
--tail N # 仅列出最新N条容器日志

注意:

ln -s /dev/stdout /var/log/nginx/access.log

查看容器进程

docker top d9e3ab321e18

更新容器选项

docker update --restart always 6d0a073d0b50
docker update --memory 50M --memory-swap 50M

提交容器为镜像

docker commit 6d0a073d0b50 test:v2

导出容器到归档文件镜像:

没有名字、标签及构建历史,所有层合并为一层,只能用import导入。

docker export 6d0a073d0b50 > docker_test.tar.gz

比较容器不同

docker diff 6d0a073d0b50

挂起容器

docker pause 6d0a073d0b50

取消挂起容器

docker unpause 6d0a073d0b50

统计容器资源

docker stats --no-stream
--no-stream # 不动,不刷新

Docker端口映射

docker run              # docker 会自动添加一条iptables规则来实现端口映射
-p hostPort:containerPort # 指定宿主机端口映射容器端口
-p ip:hostPort:containerPort # 指定IP端口映射
-p containerPort # 随机端口映射
-p ip::containerPort(随机端口:32768-60999) # 指定IP随机端口映射
-p hostPort:containerPort/udp # 使用udp协议指定IP随机端口映射
-p 80:80 -p 3306:3306 # 多次复用
-p 1111-1119:1111-1119 # 端口范围映射
-P # 自动随机端口映射

查看容器端口映射

docker port 容器ID/容器名

Docker数据卷

挂载数据卷

docker run -v 宿主机绝对路径:容器绝对路径    # 挂载宿主机的路径到容器中,可复用
docker run -v 容器目录 # 创建一个随机卷,来持久化容器的目录下的数据
docker run -v 卷名:容器目录 # 创建一个固定名字的卷,来持久化容器的目录下的数据
docker run --volumes-from 指定容器 # 挂载和指定容器相同的所有卷

可用于代码上线 nginx 静态资源共享等,类似于NFS,可以实现容器间数据共享。

复制文件

在容器和本地文件系统之间复制文件/文件夹

docker cp [OPTIONS] 容器:SRC_PATH DEST_PATH|-
docker cp [OPTIONS] SRC_PATH|- 容器:DEST_PATH

查看卷列表

docker volume ls

卷存储在:/var/lib/docker/volume


练习:只启动一个nginx容器,要求访问80端口,出现nginx默认欢迎首页;访问81端口,出现小鸟飞飞。

cat > /root/xiaoniao.conf << EOF
server {
listen 81;
server_name localhost;
location / {
root /code;
index index.html index.htm;
}
}
EOF
docker run -d -p 80-81:80-81 -v /root/xiaoniaofeifei:/code -v  /root/xiaoniao.conf:/etc/nginx/conf.d/xiaoniao.conf --name xiaoniao nginx:latest

验证:

  1. 监听端口80 81
docker ps -l -a
  1. 浏览器双窗口检查

docker system

docker system df     # 统计docker-ce使用磁盘空间
docker system prune # 清理停止的容器,未使用的网卡,无名的镜像和构建缓存
docker system info # 查看docker-ce信息
docker system even # 查看docker-ce事件

关闭docker服务,不关闭容器

cat > /etc/docker/daemon.json <<EOF
{
"live-restore": true
}
EOF

Docker服务进程

查看docker进程,了解docker的运行及工作方式

[root@docker01 ~]# pstree -p
systemd(1)─┬─VGAuthService(816)
├─abrt-watch-log(837)
├─abrtd(832)
├─agetty(848)
├─auditd(759)───{auditd}(760)
├─containerd(1390)─┬─containerd-shim(2053)─┬─bash(2069)
│ │ ├─{containerd-shim}(2054)
│ │ ├─{containerd-shim}(2055)
│ │ ├─{containerd-shim}(2056)
│ │ ├─{containerd-shim}(2057)
│ │ ├─{containerd-shim}(2058)
│ │ ├─{containerd-shim}(2059)
│ │ ├─{containerd-shim}(2061)
│ │ └─{containerd-shim}(2087)
│ ├─{containerd}(1424)
│ ├─{containerd}(1425)
│ ├─{containerd}(1426)
│ ├─{containerd}(1433)
│ ├─{containerd}(1434)
│ ├─{containerd}(1448)
│ ├─{containerd}(1452)
│ ├─{containerd}(1946)
│ └─{containerd}(1949)
├─crond(841)
├─dbus-daemon(820)
├─dockerd(1451)─┬─{dockerd}(1519)
│ ├─{dockerd}(1520)
│ ├─{dockerd}(1521)
│ ├─{dockerd}(1533)
│ ├─{dockerd}(1537)
│ ├─{dockerd}(1538)
│ ├─{dockerd}(1543)
│ ├─{dockerd}(1559)
│ └─{dockerd}(1969)

containerd进程关系

四个进程:

  • containerd:被dockerd进程调用以实现与runc交互,其父进程为宿主机的systemd守护进程 。
  • dockerd:被client直接访问,其父进程为宿主机的systemd守护进程 。
  • containerd-shim:真正运行容器的载体,其父进程为containerd。
  • docker-proxy:实现容器通信,其父进程为dockerd。

容器的创建与管理过程

通信流程:

  1. dockerd通过grpc和containerd模块通信,dockerd由libcontainerd负责和containerd进行交换,dockerd和containerd通信socket文件:/run/containerd/containerd.sock 。
  2. containerd在dockerd启动时被启动,然后containerd启动grpc请求监听,containerd 处理grpc请求,根据请求做相应动作。
  3. 若是start或是exec容器,containerd拉起一个container-shim,并进行相应的操作。
  4. container-shim被拉起后,start/exec/create拉起runC进程,通过 exit、control 文件和containerd通信,通过父子进程关系和SIGCHLD监控容器中进程状态。
  5. 在整个容器生命周期中,containerd通过epoll监控容器文件,监控容器事件。

手动制作Docker镜像

基于centos7系统的nginx镜像(单服务)

  1. 启动一个纯净的centos:7容器并进入
docker run -it -p 80:80 centos:7
  1. nginx 安装 修改首页
curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
yum install nginx -y
rm -rf /usr/share/nginx/html/index.html
echo "nginx" > /usr/share/nginx/html/index.html
exit
  1. 把安装好服务的容器,提交为镜像
docker commit a74fae23b022 centos7_nginx:v1
  1. 测试镜像的功能
docker run -d -p 80:80 centos7_nginx:v1 nginx -g 'daemon off;'
curl -I 10.0.0.11

基于centos7系统的sshd镜像(单服务)

  1. 启动一个纯净的centos:7容器并进入
docker run -it -p 100:22 centos:7
  1. sshd initscripts 安装 启动
curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
yum install initscripts openssh-server -y
/usr/sbin/sshd-keygen
echo '1'|passwd --stdin root
exit
  1. 把安装好服务的容器,提交为镜像
docker commit c83d838df822 centos7_sshd:v1
  1. 测试镜像的功能
docker run -d -p 100:22 centos7_sshd:v1 /usr/sbin/sshd -D
docker ps -al
ssh 10.0.0.11 -p100

基于centos7系统的支持ssh登录的nginx镜像(多服务)

  1. 启动一个纯净的centos:7容器并进入
docker run -it -p 100:22 -p 80:80 centos:7
  1. nginx sshd initscripts 安装 启动
curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
yum install nginx initscripts openssh-server -y
/usr/sbin/sshd-keygen
rm -rf /usr/share/nginx/html/index.html
echo "nginx" > /usr/share/nginx/html/index.html
cat > init.sh <<-EOF
#!/bin/bash
echo "\$SSH_PASS"|passwd --stdin root
nginx
/usr/sbin/sshd -D
EOF
chmod +x init.sh
exit
  1. 把安装好服务的容器,提交为镜像
docker commit 32364fd2b78f centos7_nginx_sshd:v1
  1. 测试镜像的功能
docker run -d -p 100:22 -p 80:80 -e "SSH_PASS=1" --name=cns centos7_nginx_sshd:v1 /init.sh
docker top cns
curl -I 10.0.0.11
docker ps -al
rm -rf .ssh/known_hosts
ssh 10.0.0.11 -p100

基于centos7系统的kod网盘镜像(多服务)

  1. 启动一个centos7_nginx_sshd:v1 并进入
docker run -d -p 100:22 -p 80:80 -e "SSH_PASS=1" --name=cns centos7_nginx_sshd:v1 /init.sh
docker exec -ti `docker ps -lq` /bin/bash
  1. 安装
cat > init.sh <<-EOF
#!/bin/bash
echo "\$SSH_PASS"|passwd --stdin root
nginx
/usr/sbin/php-fpm -D
/usr/sbin/sshd -D
EOF
chmod +x init.sh
echo "192.168.15.253 mirrors.aliyun.com" >> /etc/hosts
yum install php-fpm php-gd php-mbstring unzip -y
mkdir /code && cd /code
curl -o /code/kodexplorer4.40.zip http://192.168.15.253/kodexplorer4.40.zip
unzip -d /code/html kodexplorer4.40.zip
chown -R nginx:nginx /code
sed -i 's/= apache/= nginx/g' /etc/php-fpm.d/www.conf
sed -i '38,57s/^/#/g' /etc/nginx/nginx.conf
cat > /etc/nginx/conf.d/kod.conf <<-EOF
server {
listen 80;
server_name kod.oldboy.com;
root /code/html;
index index.php index.html;
client_max_body_size 100m; location / {
} 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;
}
}
EOF
exit
  1. 把安装好服务的容器,提交为镜像
docker stop `docker ps -lq`
docker commit `docker ps -lq` kod:v1
  1. 测试镜像的功能
docker rm -f `docker ps -aq`
docker run -d -p 100:22 -p 80:80 -e "SSH_PASS=1" --name=cns kod:v1 /init.sh

基于centos7系统的LNMP架构wordpress镜像(多服务)

  1. 启动一个纯净的centos:7容器并进入
docker run -it -p 100:22 -p 80:80 centos:7
docker cp /opt/dockerfile/lnmp_wordpress/latest-zh_CN.tar.gz `docker ps -lq`:/root
  1. 安装
cat > init.sh <<-EOF
#!/bin/bash
echo "\$SSH_PASS"|passwd --stdin root
/usr/libexec/mariadb-prepare-db-dir
/usr/bin/mysqld_safe --basedir=/usr &
/opt/remi/php72/root/usr/sbin/php-fpm -D
nginx
sleep 2
mysql -e 'CREATE DATABASE wordpress;GRANT ALL PRIVILEGES ON wordpress.* TO "wordpress"@"localhost" IDENTIFIED BY "1";FLUSH PRIVILEGES;'
/usr/sbin/sshd -D
EOF
chmod +x init.sh curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo && yum -y install https://rpms.remirepo.net/enterprise/remi-release-7.rpm yum install nginx initscripts openssh-server php72-php-fpm php72-php-mysqlnd mariadb-server -y && yum clean all && rm -rf /var/cache/yum/* /usr/sbin/sshd-keygen && mkdir /code && cd /code mv /root/latest-zh_CN.tar.gz . tar xf latest-zh_CN.tar.gz && rm -f latest-zh_CN.tar.gz && chown -R nginx:nginx /code && sed -i 's/= apache/= nginx/g' /etc/opt/remi/php72/php-fpm.d/www.conf && sed -i '38,57s/^/#/g' /etc/nginx/nginx.conf cat > /etc/nginx/conf.d/wordpress.conf <<-EOF
server {
listen 80;
server_name wordpress.oldboy.com;
root /code/wordpress;
index index.php index.html;
client_max_body_size 100m; location / {
} 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;
}
}
EOF exit
  1. 把安装好服务的容器,提交为镜像
docker stop `docker ps -lq`
docker commit `docker ps -lq` lnmp_wp:v1
  1. 测试镜像的功能
docker rm -f `docker ps -aq`
docker run -d -p 100:22 -p 80:80 -e "SSH_PASS=1" lnmp_wp:v1 /init.sh

自动制作Docker镜像

Docker镜像:中药

dockerfile: 配方


dockerfile常用指令

  • FROM:指定使用的基础镜像,制作基础镜像 FROM scratch
  • RUN:制作镜像过程中需要的执行命令(安装服务)
  • CMD:容器启动的时候执行的初始命令,容易被替换(启动服务)
  • ENTRYPOINT:容器启动的时候执行的初始命令,不能被替换,如果同时使用CMD和ENTRYPOINT,CMD命令将作为ENTRYPOINT命令的参数
  • ADD:把dockerfile当前目录下的文件拷贝到容器中(自动解压tar包),可使用URL作为源,制作基础镜像
  • COPY:把dockerfile当前目录下的文件拷贝到容器中(不解压tar包),支持统配符,拷贝目录,只拷贝目录下的子文件、子目录。
  • WORKDIR:指定容器的默认工作目录
  • EXPOSE:镜像监听的端口,run -P 使用
  • VOLUME:持久化卷
  • ENV:环境变量(ssh的密码,数据库的密码)
  • STOPSIGNAL:设置将被发送到容器退出的系统调用信号。该信号可以是内核syscall表中的有效无符号数字(例如9),也可以是SIGNAME格式的信号名称(例如SIGKILL)。
  • HEALTHCHECK:健康检查机制
    • --interval 间隔时间,每隔10秒执行一次脚本
    • --timeout 脚本执行超时时间
    • --retries 脚本失败次数,3次失败,即30秒之后,标记容器为unhealthy
  • LABEL: 镜像的属性标签
  • MAINTAINER:维护者标签

官方文档


自动构建镜像思路

  1. 手动制作docker镜像,记录历史命令

  2. 根据历史命令编写dockerfile文件

  3. docker build构建docker镜像

    docker build --network=host -t REPOSITORY:TAG .
  4. 测试镜像的功能


dockerfile单服务

mkdir -p /opt/dockerfile/centos7_nginx
cat > /opt/dockerfile/centos7_nginx/Dockerfile <<EOF
FROM centos:7 RUN curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
RUN curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
RUN yum install nginx -y
RUN rm -rf /usr/share/nginx/html/index.html
RUN echo "nginx" > /usr/share/nginx/html/index.html WORKDIR /root
EXPOSE 80
CMD ["nginx","-g","daemon off;"]
EOF
docker build --network=host -t centos7_nginx:v2 /opt/dockerfile/centos7_nginx/
docker run -d -p 80:80 centos7_nginx:v2
docker ps -al
curl -I 10.0.0.11

dockerfile多服务

mkdir -p /opt/dockerfile/kod
cat > /opt/dockerfile/kod/init.sh <<-EOF
#!/bin/bash
echo "\$SSH_PASS"|passwd --stdin root
nginx
/usr/sbin/php-fpm -D
/usr/sbin/sshd -D
EOF
cat > /opt/dockerfile/kod/kod.conf <<-EOF
server {
listen 80;
server_name kod.oldboy.com;
root /code/html;
index index.php index.html;
client_max_body_size 100m; location / {
} 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;
}
}
EOF
wget -O /opt/dockerfile/kod/kodexplorer4.40.zip http://192.168.15.253/kodexplorer4.40.zip
cat > /opt/dockerfile/kod/Dockerfile <<EOF
FROM centos7_nginx_sshd:v1 RUN yum install php-fpm php-gd php-mbstring unzip -y
RUN mkdir /code
WORKDIR /code
ADD init.sh /init.sh
ADD kod.conf /etc/nginx/conf.d/kod.conf
ADD kodexplorer4.40.zip /code/kodexplorer4.40.zip
RUN unzip -d /code/html kodexplorer4.40.zip
RUN rm -rf /code/kodexplorer4.40.zip
RUN sed -i 's/= apache/= nginx/g' /etc/php-fpm.d/www.conf
RUN sed -i '38,57s/^/#/g' /etc/nginx/nginx.conf
RUN chown -R nginx:nginx /code
RUN chmod +x /init.sh
ENV SSH_PASS 1
EXPOSE 22 80 CMD ["/bin/bash","/init.sh"]
EOF
docker build --network=host -t kod:v2 /opt/dockerfile/kod/
docker run -d -p 100:22 -p 80:80 -e "SSH_PASS=123" --name=cns kod:v2

dockerfile基础镜像

官方说明

mkdir -p /opt/dockerfile/base
wget -O /opt/dockerfile/base/rootfs.tar.xz https://mirrors.tuna.tsinghua.edu.cn/lxc-images/images/alpine/3.10/amd64/default/20201130_13%3A00/rootfs.tar.xz
cat > /opt/dockerfile/base/Dockerfile <<EOF
FROM scratch
ADD rootfs.tar.xz /
CMD ["/bin/sh"]
EOF
docker build -t alpine_base:v1 /opt/dockerfile/base/
docker run -it alpine_base:v1

dockerfile的wordpress镜像

MySQL镜像

docker run -it -p 100:22 -p 80:80 centos:7
mkdir -p /opt/dockerfile/lnmp_wordpress/repo
cd /opt/dockerfile/lnmp_wordpress/repo
wget http://mirrors.aliyun.com/repo/Centos-7.repo http://mirrors.aliyun.com/repo/epel-7.repo https://cn.wordpress.org/latest-zh_CN.tar.gz
cat > /opt/dockerfile/lnmp_wordpress/repo/MariaDB.repo <<EOF
[mariadb]
name=MariaDB
baseurl=https://mirrors.ustc.edu.cn/mariadb/yum/10.5/centos7-amd64/
gpgcheck=0
enabled=1
EOF
cat > /opt/dockerfile/lnmp_wordpress/repo/wordpress.conf <<-EOF
server {
listen 80;
server_name wordpress.oldboy.com;
root /code/wordpress;
index index.php index.html;
client_max_body_size 100m; location / {
} 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;
}
}
EOF
cat > /opt/dockerfile/lnmp_wordpress/repo/init.sh <<-EOF
#!/bin/bash
echo "\$SSH_PASS"|passwd --stdin root
/usr/libexec/mariadb-prepare-db-dir
/usr/bin/mysqld_safe --basedir=/usr &
/opt/remi/php72/root/usr/sbin/php-fpm -D
nginx
sleep 2
mysql -e 'CREATE DATABASE wordpress;GRANT ALL PRIVILEGES ON wordpress.* TO "wordpress"@"localhost" IDENTIFIED BY "1";FLUSH PRIVILEGES;'
/usr/sbin/sshd -D
EOF
cat > /opt/dockerfile/lnmp_wordpress/Dockerfile <<EOF
FROM centos:7
COPY repo /etc/yum.repos.d/
RUN yum -y install https://rpms.remirepo.net/enterprise/remi-release-7.rpm && \
yum install nginx initscripts openssh-server php72-php-fpm php72-php-mysqlnd mariadb-server -y && \
yum clean all && \
rm -rf /var/cache/yum/* && \
/usr/sbin/sshd-keygen && \
mkdir /code && cd /code && \
mv /etc/yum.repos.d/latest-zh_CN.tar.gz . && \
tar xf latest-zh_CN.tar.gz && \
rm -f latest-zh_CN.tar.gz && \
chown -R nginx:nginx /code && \
sed -i 's/= apache/= nginx/g' /etc/opt/remi/php72/php-fpm.d/www.conf && \
sed -i '38,57s/^/#/g' /etc/nginx/nginx.conf && \
mv /etc/yum.repos.d/wordpress.conf /etc/nginx/conf.d/wordpress.conf && \
mv /etc/yum.repos.d/init.sh /init.sh && \
chmod +x init.sh
CMD ["/init.sh"]
EOF
docker build -t lnmp_wp:v1 /opt/dockerfile/lnmp_wordpress/
docker rm -f `docker ps -aq`
docker run -d -p 100:22 -p 80:80 -e "SSH_PASS=1" --name=cns lnmp_wp:v1 /init.sh

Docker镜像的分层

Dokcer镜像含有启动容器所需要的文件系统及其内容,用于创建并启动docker容器。


Dokcer镜像采用分层构建机制,最底层为Bootfs,之上为rootfs,再额外挂载"可写"层。

  • bootfs:用于系统引导的文件系统,包括bootloader和kernel,容器启动完成后会被卸载,以节约内存资源;

  • rootfs:位于bootfs之上,表现为docker容器的根文件系统;由内核挂载为“只读”模式

  • "可写"层:通过UnionFS(联合文件系统)额外挂载的一个"可写"层;

    "可写"层之间通过parent文件中存放的父层sha256关联。

    [root@docker01 ~]# tree /var/lib/docker/image/
    /var/lib/docker/image/
    `-- overlay2 # 存储驱动
    |-- distribution
    |-- imagedb # 镜像文件
    | |-- content
    | | `-- sha256
    | | `-- aa88f087d1bcf434df7494c64931fec52782e8aa4041959bc51ee9d6bd5cdc49
    | `-- metadata
    | `-- sha256
    | |-- 7bad8e5e960f912d37ab8f7c910cbbd228129da3b0489ec885cafbd7b28ad6dd
    | | `-- parent # 父sha256
    | `-- fdb81b0740bdb34e37846eb4ded59fd1a243db356d2d309ccd51e9b0a75ad56f
    | `-- parent
    |-- layerdb
    | |-- mounts
    | | `-- d1c6a7f266126296b12ddc79ef8d26ccadd4a43f15b7f54f635239ecbdf9b09d
    | | |-- init-id
    | | |-- mount-id
    | | `-- parent
    | |-- sha256
    | | |-- d69483a6face4499acb974449d1303591fcbb5cdce5420f36f8a6607bda11854
    | | | |-- cache-id
    | | | |-- diff
    | | | |-- size
    | | | `-- tar-split.json.gz
    | | `-- fe986c7da4b1268db8eccd9cce00f27565eb3c574d6353e8d4309c2cc68fa27d
    | | |-- cache-id
    | | |-- diff # 相对于父层的不同
    | | |-- parent # 父层sha256
    | | |-- size
    | | `-- tar-split.json.gz
    | `-- tmp
    `-- repositories.json [root@docker01 ~]# cat /var/lib/docker/image/overlay2/layerdb/sha256/fe986c7da4b1268db8eccd9cce00f27565eb3c574d6353e8d4309c2cc68fa27d/parent
    sha256:d69483a6face4499acb974449d1303591fcbb5cdce5420f36f8a6607bda11854 [root@docker01 ~]# cat /var/lib/docker/image/overlay2/imagedb/metadata/sha256/fdb81b0740bdb34e37846eb4ded59fd1a243db356d2d309ccd51e9b0a75ad56f/parent
    sha256:7bad8e5e960f912d37ab8f7c910cbbd228129da3b0489ec885cafbd7b28ad6dd [root@docker01 ~]# cat /var/lib/docker/image/overlay2/imagedb/metadata/sha256/7bad8e5e960f912d37ab8f7c910cbbd228129da3b0489ec885cafbd7b28ad6dd/parent
    sha256:aa88f087d1bcf434df7494c64931fec52782e8aa4041959bc51ee9d6bd5cdc49

docker image layer

  • 位于下层的镜像成为父镜像,最底层的成为基础镜像
  • 最上层为可读写层,其下的均为只读层;


镜像构建过程

新镜像是从 base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。

Docker镜像的分层实现了资源共享,节省占用空间。


Docker存储驱动

  1. Docker默认存储驱动为overlay2需要磁盘分区支持d_type文件分层功能 ,因此需要系统磁盘的额外支持。官方文档 /var/lib/docker/overlay2

  2. Docker官方推荐首选存储驱动为overlay2,其次为devicemapper。但是devicemapper存在使用空间方面的一些限制, 虽然可以通过后期配置解决,但是官方依然推荐使用overlay2。

注意:

  • 如果docker数据目录是一块单独的xfs格式的磁盘分区,那么需要在格式化时加上参数 -n ftype=1,否则后期在启动容器的时候会报错不支持d_type

  • centos7.2 版本后默认 ftype=1

    [root@docker01 ~]# xfs_info /
    meta-data=/dev/mapper/centos-root isize=512 agcount=4, agsize=1232128 blks
    = sectsz=512 attr=2, projid32bit=1
    = crc=1 finobt=0 spinodes=0
    data = bsize=4096 blocks=4928512, imaxpct=25
    = sunit=0 swidth=0 blks
    naming =version 2 bsize=4096 ascii-ci=0 ftype=1
    log =internal bsize=4096 blocks=2560, version=2
    = sectsz=512 sunit=0 blks, lazy-count=1
    realtime =none extsz=4096 blocks=0, rtextents=0

dockerfile的优化

优化原则:构建速度尽可能快,镜像体积尽可能小

  1. 使用小体积镜像:alpine > debian > ubuntu > centos

  2. 尽量减少中间图层(仅RUN,COPY和ADD指令创建图层)

    FROM ubuntu:18.04
    COPY . /app
    RUN make /app
    CMD python /app/app.py
  3. 利用构建缓存:修改dockerfile时,尽可能把修改的内容放在最后

  4. 使用.dockerignore文件,构建docker镜像时,排除当前目录下不需要的文件

    cat > .dockerignore <<-EOF
    filename
    EOF

容器间的互联

即在同一个宿主机上的容器之间,可以通过自定义的容器名称相互访问 。

docker run --link 容器名:容器别名(单向指定,正在运行)

zabbix容器部署

https://www.zabbix.com/documentation/4.0/zh/manual/installation/containers

docker run --name mysql-server -it \
-e MYSQL_DATABASE="zabbix" \
-e MYSQL_USER="zabbix" \
-e MYSQL_PASSWORD="zabbix_pwd" \
-e MYSQL_ROOT_PASSWORD="root_pwd" \
-d mysql:5.7 \
--character-set-server=utf8 --collation-server=utf8_bin docker run --name zabbix-java-gateway -t \
-d zabbix/zabbix-java-gateway:latest docker run --name zabbix-server-mysql -t \
-e DB_SERVER_HOST="mysql-server" \
-e MYSQL_DATABASE="zabbix" \
-e MYSQL_USER="zabbix" \
-e MYSQL_PASSWORD="zabbix_pwd" \
-e MYSQL_ROOT_PASSWORD="root_pwd" \
-e ZBX_JAVAGATEWAY="zabbix-java-gateway" \
--link mysql-server:mysql \
--link zabbix-java-gateway:zabbix-java-gateway \
-p 10051:10051 \
-d zabbix/zabbix-server-mysql:latest docker run --name zabbix-web-nginx-mysql -t \
-e DB_SERVER_HOST="mysql-server" \
-e MYSQL_DATABASE="zabbix" \
-e MYSQL_USER="zabbix" \
-e MYSQL_PASSWORD="zabbix_pwd" \
-e MYSQL_ROOT_PASSWORD="root_pwd" \
--link mysql-server:mysql \
--link zabbix-server-mysql:zabbix-server \
-p 80:80 \
-d zabbix/zabbix-web-nginx-mysql:latest

wordpress容器部署

 docker run --name mysql-server-wp -it \
-e MYSQL_DATABASE="wordpress" \
-e MYSQL_USER="wordpress" \
-e MYSQL_PASSWORD="1" \
-e MYSQL_ROOT_PASSWORD="root_pwd" \
-d mysql:5.7 \
--character-set-server=utf8 --collation-server=utf8_bin docker run --name wordpress -p 81:80 \
--link mysql-server-wp:mysql \
-e WORDPRESS_DB_NAME=wordpress \
-e WORDPRESS_DB_HOST=mysql \
-e WORDPRESS_DB_USER=wordpress \
-e WORDPRESS_DB_PASSWORD=1 \
-d wordpress:latest

docker-compose 单机版容器编排

Compose是一个用于定义和运行多容器Docker应用程序的工具。使用Compose,您可以使用Compose文件来配置应用程序的服务。然后,使用单个命令,您可以从配置中创建并启动所有服务。

Compose非常适合开发,测试和登台环境以及CI工作流程。

(1)使用Compose基本上是一个三步过程

  1. 定义您的应用程序环境 Dockerfile,以便可以在任何地方进行复制。
  2. 定义构成应用程序的服务 docker-compose.yml,以便它们可以在隔离环境中一起运行。
  3. 最后,运行docker-compose up,Compose将启动并运行整个应用程序。

(2)docker-compose.yml 示例: Compose文件参考

version: '3'

services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
redis:
image: redis

(3)Compose具有管理应用程序整个生命周期的命令:

  • 启动,停止和重建服务
  • 查看正在运行的服务的状态
  • 流式传输运行服务的日志输出
  • 在服务上运行一次性命令

(4)Docker Compose 升级

  如果从Compose 1.2或更早版本升级,请在升级Compose后删除或迁移现有容器。因为从1.3版本开始,Compose使用Docker标签来跟踪容器,并且需要重新创建容器以添加标签。

  如果Compose检测到没有标签创建的容器,它将拒绝运行,您最终不会使用两组。如果要继续使用现有容器(例如,因为它们具有要保留的数据卷),可以使用Compose 1.5.x使用以下命令迁移它们:

docker-compose migrate-to-labels

或者,如果您不担心保留它们,可以将它们删除。撰写只是创建新的。

docker container rm -f -v myapp_web_1 myapp_db_1 ...

安装

  • Docker Compose 依靠 Docker Engine 工作。

  要以非root用户身份运行Compose,请参阅以非root用户身份管理Docker

  • yum安装依赖epel源
yum install docker-compose -y

批量创建并启动

docker-compose up -d
-d # 后台启动

以目录分隔组,只读取当前目录下的 docker-compose.yml、docker-compose.yaml 文件

批量停止并删除

docker-compose down

批量启动

docker-compose start

批量停止

docker-compose stop

批量重启

docker-compose restart

指定批量规模

docker-compose scale zabbix-java-gateway=2

zabbix容器批量部署yml

mkdir -p /opt/docker-compose/zabbix && cd /opt/docker-compose/zabbix
cat > /opt/docker-compose/zabbix/docker-compose.yml <<EOF
version: '3' services:
mysql-server:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: root_pwd
MYSQL_DATABASE: zabbix
MYSQL_USER: zabbix
MYSQL_PASSWORD: zabbix_pwd
command: --character-set-server=utf8 --collation-server=utf8_bin zabbix-java-gateway:
image: zabbix/zabbix-java-gateway:latest
restart: always zabbix-server:
depends_on:
- mysql-server
image: zabbix/zabbix-server-mysql:latest
restart: always
environment:
DB_SERVER_HOST: mysql-server
MYSQL_DATABASE: zabbix
MYSQL_USER: zabbix
MYSQL_PASSWORD: zabbix_pwd
MYSQL_ROOT_PASSWORD: root_pwd
ZBX_JAVAGATEWAY: zabbix-java-gateway
ports:
- "10051:10051" zabbix-web-nginx-mysql:
depends_on:
- zabbix-server
image: zabbix/zabbix-web-nginx-mysql:latest
ports:
- "80:80"
restart: always
environment:
DB_SERVER_HOST: mysql-server
MYSQL_DATABASE: zabbix
MYSQL_USER: zabbix
MYSQL_PASSWORD: zabbix_pwd
MYSQL_ROOT_PASSWORD: root_pwd
EOF

wordpress容器批量部署yml

mkdir -p /opt/docker-compose/wordpress && cd /opt/docker-compose/wordpress
cat > /opt/docker-compose/wordpress/docker-compose.yml <<EOF
version: '3' services:
mysql:
image: mysql:5.7
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: root_pwd
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: 1
command: --character-set-server=utf8 --collation-server=utf8_bin wordpress:
depends_on:
- mysql
image: wordpress:latest
volumes:
- wordpress_files:/var/www/html
ports:
- "81:80"
restart: always
environment:
DB_SERVER_HOST: mysql
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: 1
volumes:
wordpress_files:
db_data:
EOF

registry 私有仓库

启动私有仓库

docker run -d -p 5000:5000 --restart=always --name registry -v /opt/myregistry:/var/lib/registry registry

上传镜像

docker 解析镜像名指定上传路径,所以首先必须指定标签

docker tag alpine:3.9 10.0.0.11:5000/alpine:3.9
docker push 10.0.0.11:5000/alpine:3.9

注意:

默认使用https协议上传,若使用http协议会报错,修改配置文件,指定信任地址,重启docker服务。

cat > /etc/docker/daemon.json <<EOF
{
"registry-mirrors": ["https://registry.docker-cn.com"],
"insecure-registries": ["10.0.0.11:5000"]
}
EOF
systemctl restart docker

下载镜像

docker pull 10.0.0.11:5000/alpine:3.9

私有仓库操作

查看私有仓库镜像列表:http://10.0.0.11:5000/v2/_catalog

查看私有仓库镜像版本:http://10.0.0.11:5000/v2/alpine/tags/list

删除私有仓库镜像

  1. 进入docker registry容器中
docker exec -it registry /bin/sh
  1. 删除私有仓库镜像目录
rm -fr /var/lib/registry/docker/registry/v2/repositories/alpine
  1. 清除无用私有仓库镜像blob
registry garbage-collect /etc/docker/registry/config.yml

使用安全认证

  1. 生成密码
yum install httpd-tools -y
mkdir /opt/registry-auth/ -p
htpasswd -Bbn oldguo 123 > /opt/registry-auth/htpasswd
  1. 重新启动带有秘钥功能的registry容器
docker rm -f `docker ps -aq`
docker run -d -p 5000:5000 -v /opt/registry-auth/:/auth/ -v /opt/registry:/var/lib/registry --name register-auth -e "REGISTRY_AUTH=htpasswd" -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" -e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" registry
  1. 上传下载镜像,需要先login
[root@docker02 ~]# docker login 10.0.0.100:5000
Username: oldguo
Password:

harbor 企业级私有仓库

Harbor介绍

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

  • Harbor是一个开源的可信云本机注册表项目,用于存储,签名和扫描内容。Harbor通过添加用户通常需要的功能(如安全性,身份和管理)来扩展开源Docker Distribution。
  • Harbor Gitlab由Cloud Native Computing Foundation(CNCF)托管。

Harbor功能

  • 基于角色的访问控制:用户与Docker镜像仓库通过“项目”进行组织管理,一个用户可以对多个镜像仓库在同一命名空间(project)里有不同的权限。

  • 基于策略的镜像复制:可以基于具有多个过滤器(存储库,标记和标签)的策略在多个注册表实例之间复制(同步)映像。如果遇到任何错误,Harbor将自动重试进行复制。非常适合负载平衡,高可用性,多数据中心,混合和多云场景。

  • 图形化用户界面:用户可以通过浏览器来浏览,检索当前Docker 镜像仓库,管理项目和命名空间。

  • AD/LDAP支持:Harbor与现有企业LDAP / AD集成以进行用户身份验证和管理,并支持将LDAP组导入Harbor并为其分配适当的项目角色。

  • 审计管理:所有针对镜像仓库的操作都可以被记录追溯,用于审计管理。

  • 国际化:已拥有英文、中文、德文、日文和俄文的本地化版本。更多的语言将会添加进来。

  • RESTful API :提供给管理员对于 Harbor 更多的操控 , 使得与其它管理软件集成变得更容易。

  • 部署简单:提供在线和离线两种安装工具,也可以安装到vSphere平台(OVA方式)虚拟设备。

  • 云本机注册表:Harbour 支持容器映像和Helm图表,可用作云本机环境(如容器运行时和业务流程平台)的注册表。

  • 漏洞扫描:Harbor定期扫描图像并警告用户漏洞。

  • 镜像删除和垃圾收集:可以删除镜像,并可以回收它们的空间。

  • 公证:可以确保图像的真实性。

安装

  1. 下载离线包
cd /opt
wget https://github.com/goharbor/harbor/releases/download/v1.10.6/harbor-offline-installer-v1.10.6.tgz
  1. 解压
tar xf harbor-offline-installer-*.tgz
  1. 安装依赖

    • docker-ce 17.06.0 +
    • docker-compose 1.18.0+
yum install docker-ce docker-compose -y
  1. 创建并修改配置文件,设置主机IP和密码,注释https
cp /opt/harbor/harbor.yml.tmpl /opt/harbor/harbor.yml
vim /opt/harbor/harbor.yml
hostname: 10.0.0.12
... ...
#https:
# # https port for harbor, default is 443
# port: 443
# # The path of cert and key files for nginx
# certificate: /your/certificate/path
# private_key: /your/private/key/path
... ...
harbor_admin_password: 123456
  1. 执行安装脚本

    • 执行前80端口不能被占用!!!
harbor/install.sh
  1. 注意:管理使用docker-compose
cd /opt/harbor
docker-compose stop
docker-compose start
  1. 设置开机启动
cat >> /etc/rc.d/rc.local <<EOF
cd /opt/harbor && docker-compose start
EOF
chmod +x /etc/rc.d/rc.local

http上传镜像

  1. 设置http信任,重启docker
cat > /etc/docker/daemon.json <<EOF
{
"registry-mirrors": ["https://registry.docker-cn.com"],
"insecure-registries": ["10.0.0.12"]
}
EOF
systemctl restart docker
  1. 登录harbor,用户名:admin,密码:123456
docker login 10.0.0.12

密码保存在/root/.docker/config.json文件中

  1. 指定标签,上传镜像
docker tag alpine:3.9 10.0.0.12/library/alpine:3.9
docker push 10.0.0.12/library/alpine:3.9
  1. 登录网页http://10.0.0.12查看

使用https

  1. 修改配置文件:使用域名,指定https证书的公钥和私钥
vim /opt/harbor/harbor.yml
hostname: blog.oldqiang.com
... ...
https:
# https port for harbor, default is 443
port: 443
# The path of cert and key files for nginx
certificate: /opt/cert/Nginx/1_blog.oldqiang.com_bundle.crt
private_key: /opt/cert/Nginx/2_blog.oldqiang.com.key

使用自签名证书:

Step1:创建证书存放目录

mkdir -p /data/cert && cd /data/cert

Step2:创建自己的CA证书(不使用第三方权威机构的CA来认证)

openssl genrsa -out ca.key 2048   # 生成根证书私钥(无加密)

Step3:生成自签名证书(使用已有私钥ca.key自行签发根证书)

openssl req -x509 -new -nodes -key ca.key -days 10000 -out ca.crt -subj "/CN=Harbor-ca"

req      # 产生证书签发申请命令
-x509 # 签发X.509格式证书命令。X.509是最通用的一种签名证书格式。
-new # 生成证书请求
-key # 指定私钥文件
-nodes # 表示私钥不加密
-out # 输出
-subj # 指定用户信息
-days # 有效期

Step4:生成服务器端私钥和CSR签名请求

openssl req -newkey rsa:4096 -nodes -sha256 -keyout server.key -out server.csr

Step5:签发服务器证书

echo subjectAltName = IP:10.0.0.12 > extfile.cnf
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -days 365 -extfile extfile.cnf -out server.crt x509 # 签发X.509格式证书命令。
-req # 表示证书输入请求。
-days # 表示有效天数
-extensions # 表示按OpenSSL配置文件v3_req项添加扩展。
-CA # 表示CA证书,这里为ca.crt
-CAkey # 表示CA证书密钥,这里为ca.key
-CAcreateserial # 表示创建CA证书序列号
-extfile # 指定文件

Step6:客户端设置docker证书

# 如果如下目录不存在,请创建,如果有域名请按此格式依次创建
mkdir -p /etc/docker/certs.d/10.0.0.12
# mkdir -p /etc/docker/certs.d/[IP2]
# mkdir -p /etc/docker/certs.d/[example1.com]
# 如果端口为443,则不需要指定。如果为自定义端口,请指定端口
# /etc/docker/certs.d/yourdomain.com:port # 将ca根证书依次复制到上述创建的目录中
cp ca.crt /etc/docker/certs.d/10.0.0.12/

Step7:为harbor生成配置文件

./prepare
  1. 注释安装脚本中的导入镜像步骤
sed -i 's/docker load/#&/' /opt/harbor/install.sh
  1. 执行安装脚本
/opt/harbor/install.sh
  1. windows配置hosts解析
C:\Windows\System32\drivers\etc\hosts
10.0.0.12 blog.oldqiang.com
  1. 登录网页https://blog.oldqiang.com查看
  2. docker01配置hosts解析
cat >> /etc/hosts <<EOF
10.0.0.12 blog.oldqiang.com
EOF
  1. docker01删除http信任,重启docker
rm -rf /etc/docker/daemon.json
systemctl restart docker
  1. docker01登录harbor,用户名:admin,密码:123456
docker login blog.oldqiang.com
  1. docker01上传镜像
docker tag nginx:latest blog.oldqiang.com/library/nginx:latest
docker push blog.oldqiang.com/library/nginx:latest

Harbor配置参数

位于harbor.cfg文件中。

  • required参数:需要在配置文件中设置这些参数。如果用户更新它们harbor.cfg并运行install.sh脚本以重新安装Harbor,它们将生效。
  • 可选参数:用户可以将它们保留为默认值,并在启动Harbour后在Web Portal上更新它们。如果它们已经启用harbor.cfg,它们只会在首次启动Harbour时生效。harbor.cfg将忽略对这些参数的后续更新。

注意:

  • 至少需要更改hostname属性。

  • 如果您选择通过Portal设置这些参数,请务必在Harbour启动后立即执行此操作。特别是,您必须在Harbour中注册或创建任何新用户之前设置所需的auth_mode。当系统中有用户时(除默认管理员用户外), 无法更改auth_mode。

必需参数