docker
背景
环境配置的难题
- 软件开发最大的麻烦事之一,就是环境配置.用户计算机的环境都不相同
- 如果某些老旧的模块与当前环境不兼容,那就麻烦了
- 环境配置如此麻烦,换一台机器,就要重来一次,旷日费时
- 能不能从根本上解决问题,软件可以带环境安装?
虚拟机
-
虚拟机(virtual machine)就是带环境安装的一种解决方案
-
它可以在一种操作系统里面运行另一种操作系统,比如在 Windows 系统里面运行 Linux 系统
-
用户可以通过虚拟机还原软件的原始环境.但是,这个方案有几个缺点
-
缺点
-
资源占用多
- 虚拟机会独占一部分系统资源,它运行的时候,其他程序就不能使用这些资源了
-
冗余步骤多
- 虚拟机是完整的操作系统,一些系统级别的操作步骤,往往无法跳过,比如用户登录等, 操作繁琐
-
启动慢
- 启动操作系统需要多久,启动虚拟机就需要多久. 可能要等几分钟,应用程序才能真正运行
Docker出现的背景
- 每个集群都需要搭建很多虚拟机,再加上备份,本地磁盘很快被一大堆虚拟机镜像占满
- 虚拟机共用,不同项目的应用不兼容,互相干扰影响
- 环境不同导致代码不能正常运行,为了兼容特殊环境需要对代码进行定制化修改
- 升级或迁移项目操作繁琐,更换环境需要重新测试,费时费力
docker简介
Docker 是什么
容器
Container
Docker
-
DotCloud公司结合LXC和以下列出的技术实现了Docker容器引擎,相比于LXC,Docker具备更加全面的资源控制能力,是一种应用级别的容器引擎
-
技术
-
Namespace、Cgroup
-
Chroot
- 在容器里构造完整的Linux文件系统。Chroot可以增进系统的安全性,限制使用者能做的事
-
Veth
- 在主机上虚拟出一张网卡与容器里的eth0网卡进行桥接,实现容器与主机、容器之间的网络通信
-
UnionFS
- 联合文件系统,Docker利用该技术“Copy on Write”的特点实现容器的快速启动和极少的资源占用
-
Iptables/netfilter
-
Tc
- 该技术主要用来做流量隔离,限制带宽(Tc 命令用于Linux内核的流量控制)
-
Quota
-
Setrlimit
- 该技术用来限制容器中打开的进程数,限制打开的文件个数等
-
因为Docker依赖Linux内核的技术,3.8及以上内核版本才能运行Docker容器,官方推荐至少3.10
-
Docker本质是宿主机上的一个进程,Docker通过Namespace实现环境隔离,通过Cgroup实现资源限制
Docker与openstack
Docker与虚拟机
-
架构图
-
Hypervisor
-
传统的虚拟化技术在虚拟机VM和硬件之间加了一个软件层Hypervisor(虚拟机管理程序)
-
运行方式
- 直接运行在物理硬件之上。如基于内核的KVM虚拟机,需要CPU支持虚拟化技术
- 运行在另一个操作系统。如VMWare和VitrualBox等虚拟机
-
GuestOS通过Hypervisor分享硬件,Guest OS发出的指令需要被Hypervisor捕获,然后翻译为物理硬件或宿主机操作系统能够识别的指令
-
故像 VMWare和VirtualBox等虚拟机在性能方面远不如裸机,但基于硬件虚拟化的KVM约能发挥裸机80%的性能
-
Docker Engine
- Docker引擎运行在操作系统上,是基于内核的LXC、Chroot等技术实现容器的环境隔离和资源控制
- 在容器启动后,容器里的进程直接与内核交互,无需经过Docker引擎中转,因此几乎没有性能损耗,能发挥出裸机的全部性能
- 由于Docker是基于Linux内核技术实现容器化,因此容器只能运行在Linux内核的操作系统上
- 目前在Window上安装的Docker引擎其实是利用了Window自带的Hyper-V虚拟化工具创建了一个Linux系统,容器内的操作实际上是使用这个虚拟系统实现的
-
比较
-
占用资源
- Docker的架构可以共用一个内核与共享应用程序库,所占内存极小,对系统的利用率非常高
-
创建、启动时间
-
性能损耗
- Docker容器和内核交互,几乎没有性能损耗,虚拟机需要通过Hypervisor转发,性能损耗较大
-
交付、部署
- Docker在Dockerfile中记录了容器构建过程,可在集群中实现快速分发和快速部署
- 虚拟机可以通过镜像实现环境交付的一致性,但镜像分发无法体系化
-
高可用和可恢复性
- Docker对业务的高可用支持是通过快速重新部署实现的
- 拟化具备负载均衡、高可用、容错、迁移和数据保护等成熟保障机制
-
隔离性
- Docker属于进程之间的隔离,虚拟机可实现系统级别隔离
-
安全性
- Docker的租户root和宿主机root等同,虚拟机租户root权限和宿主机的root权限是分离的
-
可管理性
- Docker的集中化管理工具还不算成熟。各种虚拟化技术都有成熟的管理工具
使用场景
- 使用系统镜像创建容器,当作虚拟机来使用,可以启动大量的操作系统容器,方便进行各种测试
- 作为云主机使用结合Kubernetes这样的容器管理系统,可以在大量服务器上动态分配和管理容器
- 应用服务打包,能很方便的升级服务和控制版本
- 容器云服务CaaS(容器即服务)
- CI/CD自动化,线上线下环境统一,线上服务版本与Git/SVN发布分支实现统一
- 解决微服务架构的实施难题
- 构建临时的运行环境,执行完任务后关闭容器即可,方便快捷
- 多租户环境为不同的租户提供独占的容器,实现简单而且成本较低
Docker安装
版本说明
- 开源的商业产品,从1.13.x开始版本分为企业版EE(Enterprise Edition)和社区版CE(Community Edition),版本号改为按照时间线,比如17.03就是2017年3月
- 社区版分为stable和edge两种发布方式,stable(稳定版)是季度发布,比如17.03, 17.06, 17.09,edge是月份发布,比如17.03, 17.04
服务架构
- C/S结构。Docker客户端与Docker服务器进行交互,Docker服务端负责构建,运行和分发Docker镜像
- Docker客户端和服务端可以运行在一台机器上,也可以通过RESTful、stock或网络接口与远程Docker服务端进行通信
安装
-
docker源
-
curl https://gitee.com/leedon21/k8s/raw/master/docker-ce.repo -o /etc/yum.repos.d/docker-ce.repo
-
yum list docker-ce --showduplicates
-
yum install -y docker-ce
-
yum install -y docker-ce-19.03.15
-
rpm包
启动
- systemctl start docker;systemctl enable docker
镜像加速器
-
方法1
-
vim /etc/docker/daemon.json
{
“registry-mirrors”: [“https://jvfknb9j.mirror.aliyuncs.com”,“https://pf5f57i3.mirror.aliyuncs.com”]
}
- systemctl restart docker
-
方法2
-
vim /usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd --registry-mirror=https://pf5f57i3.mirror.aliyuncs.com
- systemctl daemon-reload;systemctl restart docker
- 可以登录阿里云控制台, 搜索容器镜像服务, 来获取自己的镜像加速地址
查看
- docker version
- docker info
远程连接
-
vim /usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://1.1.1.11:2375 --containerd=/run/containerd/containerd.sock
-
systemctl daemon-reload;systemctl restart docker
-
docker -H 1.1.1.11 version
-
默认只能使用本机客户端连接,不建议开启远程连接,没有任何加密认证过程
-
请务必要开启需要安全认证的tcp端口https://blog.csdn.net/qq_21187515/article/details/90262324
Docker基本概念
Docker镜像(image)
- Docker把应用程序及其依赖,打包在image里面.只有通过镜像,才能生成Docker容器
- Image可以看作是容器的模板. 一个image可以生成多个同时运行的容器实例
- 实际开发中, 一个image往往通过继承另一个image, 加上一些个性化设置而生成,比如在centos镜像中加入apache形成新的apache镜像
- Image是通用的, 一台机器的image拷贝到另一台机器, 照样可以使用
- 为了方便共享,image制作完成后,可以上传到网上的仓库.Docker的官方仓库Docker Hub(hub.docker.com)是最重要、最常用的image仓库
Docker容器(container)
- Docker利用容器来运行应用,容器是从镜像创建的运行实例,它可以被启动、开始、停止、 删除。每个容器都是相互隔离的、保证安全的平台
- 可以把容器看做是一个简易版的Linux环境(包括root用户权限,进程空间,用户空间和网络空间等)和运行在其中的应用程序
- 镜像是只读的,容器在启动的时候创建一层可写层作为最上层
- docker容器启动后,会生成一个容器ID号,一旦容器内前台运行的程序结束后,容器就会关闭
- 如果不希望容器自动结束,我们需要在容器启动时给它一个前台运行的、不会自动结束的进程
Docker仓库
- 仓库是集中存放镜像的场所,分为公开仓库(Public)和私有仓库(Private) 。有时候会把仓库和仓库注册服务器(Registry)混为一谈,并不严格区分
- 最大的公开仓库是Docker Hub(hub.docker.com),存放了数量庞大的镜像供用户下载。 国内的公开仓库包括阿里云, 腾讯云, 网易蜂巢, daocloud等
- 用户可以在本地网络内创建私有仓库,可以将自己的镜像使用push命令上传到公有或者私有仓库, 使用时只需从仓库上pull下来
- Docker仓库的概念跟Git类似,注册服务器可以理解为GitHub这样的托管服务
- 仓库注册服务器( Registry)存放仓库,仓库存放镜像,镜像有不同的标签(tag)
Docker引擎
- 创建和管理容器的工具,通过读取镜像来生成容器,并负责从仓库拉取镜像或提交镜像到仓库中
Dockerfile
- Dockerfile构建出Docker镜像,通过Docker镜像运行Docker容器
关系图
docker基础系统镜像
busybox
- 一个极简版的Linux系统,集成了100多种常用Linux命令,大小不到2MB,被称为“Linux系统的瑞士军刀”,适用于简单测试场景
alpine
- 一个面向安全的轻型Linux发行版系统,比BusyBox功能更完善,大小不到5MB,是官网推荐的基础镜像,由于其包含了足够的基础功能和体积较小,在生产环境中最常用
debian/ubuntu
- Debian系列操作系统,功能完善,大小约170MB,适合研发环境
centos/fedora
- 都是基于Redhat的Linux发行版,企业级服务器常用操作系统,稳定性高,大小约200MB,适合生产环境使用
docker基本操作
Docker镜像
-
镜像索引
-
查看镜像
-
查看本机的镜像
- docker image ls
- docker images
-
镜像详细信息
-
查找镜像
-
docker search centos
- 在官方注册服务器查找centos仓库,OFFICIAL为[OK]表示是官方仓库
-
https://hub.docker.com
- 使用镜像前先看描述信息Description,找使用方法
-
下载镜像
-
上传镜像
-
删除镜像
- docker image rm 镜像
- docker rmi 镜像
Docker容器
-
容器索引
-
查看容器
-
docker ps [-a]
-
查看正在运行的[所有的]容器
-
状态
- running、exited、created、paused
-
docker ps -q [-a]
-
docker top 容器
-
docker inspect 容器
-
docker logs 容器
-
创建并运行容器
-
语法
- docker run [OPTIONS] IMAGE [COMMAND]
- [COMMAND]的输出保存在容器日志中
- 若本地没有该镜像,run会自动先下载
-
选项
-
-i
-
-t
-
-d
-
-h
-
–rm
- 容器停止后删除掉,默认不会删除
- docker run --rm -it alpine sh #用于测试用运行一次性容器
-
–name
-
–network
-
–ip
-
-p <宿主端口>:<容器端口>
- 将容器指定端口映射到宿主机的指定端口. 可以用多个-p选项指定多个端口映射
-
-p <容器端口>
-
-P
-
-v <宿主目录>:<容器目录>
- 将容器的指定目录映射到宿主机的指定目录(容器数据持久化)
-
-v <容器目录>
-
–restart=always
- 重启docker后自动启动容器,否则重启docker所有容器会停止
-
–privileged
- 需要修改某些特定的参数需要加上此选项, 正常运行一个容器不建议开放
-
示例
- docker run -itd --name centos centos:7
- docker run -d --name nginx nginx
- docker run -d --name nginx1 -p 8080:80 -v /www:/usr/share/nginx/html nginx
-
连接容器
-
容器运行
-
删除容器
-
复制文件
-
容器提交
- 对容器所作的修改保存在容器中, 一旦容器被删除了, 修改也没有了。为了永久保存, 可以将容器打包成镜像
- docker commit -m “描述信息” 容器 镜像名[:tag]
docker容器的运行过程
-
创建和运行
-
create
-
start
-
run
- None—created—start—running
-
运行和停止
-
重启
-
restart
- running—die—start—running
-
暂停
docker导入导出
基于镜像
-
导出
- docker save centos:latest > /bak/docker-centos_latest.tar
-
导入
- docker load < /bak/docker-centos_latest.tar
基于容器
-
导出
- docker export centos7 > /bak/docker-centos7.tar
-
导入
- docker import /bak/centos7.tar centos7
- 导入了镜像,对镜像有一定的改变,run后面要接命令才能运行
不建议直接导入导出,建议使用仓库
docker仓库
普通仓库
-
安装
- docker run -d -p 5000:5000 -v /docker/images/:/var/lib/registry --name registry --restart=always registry
- 通过运行registry注册服务器镜像,仓库存放在注册服务器中(registry容器的/var/lib/registry目录下)
- 为了便于使用,将容器的服务端口(5000)映射到宿主机,将仓库目录映射到宿主机目录(自定义)
-
配置
- Registry为了安全性考虑,默认需要https证书支持,可以通过修改启动文件添加允许的’不安全的’注册服务器
-
vim /usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --insecure-registry=1.1.1.11:5000
- systemctl daemon-reload;systemctl restart docker
-
使用
-
重命名镜像,使之与registry匹配
- docker tag centos:7 1.1.1.11:5000/centos7:v1
- 普通仓库不需要用户
-
上传到私有仓库
- docker push 1.1.1.11:5000/centos7:v1
-
查看私有仓库
-
从私有仓库中拉取镜像
- docker pull 1.1.1.11:5000/centos7:v1
-
WebUI
-
目的
- docker命令行工具对registry操作不能直观地查看资源,可以借助UI工具管理镜像
-
工具
-
docker-registry-web
- https://hub.docker.com/r/hyper/docker-registry-web/
-
运行
-
访问web界面
企业级仓库-Harbor
-
Harbor简介
-
官网
-
由VMware公司中国团队为企业用户设计的Registry server开源项目
-
Harbor是构建企业级私有docker镜像的仓库的开源解决方案,它是Docker Registry的更高级封装
-
支持安装在多个 Registry 节点的镜像资源复制,镜像全部保存在私有 Registry 中
-
提供了高级的安全特性,诸如用户管理,访问控制和活动审计等
-
Harbor架构
-
proxy
- 前端代理,主要是分发前端页面ui访问和镜像上传和下载流量
-
ui
- web管理页面,包括一个前端页面和后端API,底层使用mysql数据库
-
registry
- 镜像仓库,负责存储镜像文件,当镜像上传完毕后通过hook通知ui创建repository,registry的token认证也是通过ui组件完成
-
adminserver
- 系统的配置管理中心附带检查存储用量,ui和jobserver启动时候需要加载adminserver的配置
-
jobsevice
- 负责镜像复制工作的,他和registry通信,从一个registry pull镜像然后push到另一个registry,并记录job_log
-
log
- 日志汇总组件,通过docker的log-driver把日志汇总到一起
-
准备工作
- 配置好epel源,删除前面自己配置的registry
-
配置过程
-
安装docker-compose
- docker提供的一个命令行工具,用来定义和运行由多个容器组成的应用
- 可以通过YAML文件声明式的定义应用程序的各个服务,并由单个命令完成应用的创建和启动
- yum install -y docker-compose
-
下载harbor
- wget https://storage.googleapis.com/harbor-releases/release-1.9.0/harbor-offline-installer-v1.9.1.tgz
- tar xf harbor-offline-installer-v1.9.1.tgz -C /usr/local
-
配置并安装
-
cd /usr/local/harbor/
-
[root@docker harbor]# vim harbor.yml
hostname: 1.1.1.11
-
[root@docker harbor]# ./prepare
-
[root@docker harbor]# ./install.sh
-
添加http注册服务器
-
进入web界面
-
1.1.1.11
- 用户名: admin
- 密码: 见配置文件Harbor12345
-
测试上传镜像
-
登录harbor的Web界面,创建一个项目sdc
-
打标签
- docker tag nginx 1.1.1.11/sdc/nginx:v1
-
登录镜像库
-
docker login 1.1.1.11
- Username:admin
- password:Harbor12345
-
上传镜像
- docker push 1.1.1.11/sdc/nginx:v1
-
harbor启停
-
启动
- [root@docker ~]# cd /usr/local/harbor/
[root@docker harbor]# docker-compose up -d
-
关闭
- [root@docker ~]# cd /usr/local/harbor/
[root@docker harbor]# docker-compose stop
-
配置HTTPS
-
服务端
- 申请证书
- 将证书和私钥文件放到相应的位置, 并修改配置文件
https:
port: 443
certificate: /your/certificate/path
private_key: /your/private/key/path - 重新在harbor目录中执行./install.sh
-
客户端
-
创建证书目录
- mkdir -p /etc/docker/certs.d
-
将证书放到证书目录中
-
权限管理
-
官方文档
- https://goharbor.io/docs/1.10/administration/managing-users/
-
系统级别
-
项目级别
-
项目管理员
- 当用户创建一个项目后,此用户为该项目的项目管理员, 项目管理员拥有该项目的一切权限
-
项目维护者
- 拥有比“开发人员”更高的权限,包括查找镜像、查看复制任务、删除镜像的能力
-
开发者
-
访客
- 对指定项目具有只读权限。他们可以拉出和重新标记镜像,但不能推
公有仓库-阿里云
-
登录阿里云控制台
-
搜索 容器镜像服务 并进入
-
创建个人实例
- 实例列表 -> 个人实例 -> + 创建个人实例 -> 进入个人实例
-
创建命名空间
- 命名空间->创建命名空间->自定义命名空间->确定
- 全局唯一,类似于harbor中的项目,用来对应一个公司、组织或个人用户
-
创建镜像仓库
- 镜像仓库->创建镜像仓库->选择命名空间->自定义仓库->选择代码源(本地仓库)->创建镜像仓库
docker数据持久
介绍
- 容器的生命周期是有限的,一旦一个容器被删除,那么容器中的数据随之而删除了
- 如果想要永久保存容器中的数据,则需要将数据保存在宿主机的目录中,这就是Docker的数据持久化
- Docker的数据持久化主要有两种方式:bind mount、volume
bind mount
-
用法
-
注意
- host机器的目录路径必须为绝对路径(准确的说需要以/或~/开始的路径)
- 如果目录(不论哪边)不存在,docker会自动创建该目录
- host上的目录的内容会覆盖掉容器目录的内容
-
缺陷
- 移植性差,如果两个系统的目录结构不同(如windows与linux)则不可移植
volume
-
用法
-
-v [VOLUME_NAME:]容器目录[:挂载属性]
-
docker run -d -v nginx:/usr/share/nginx/html nginx
-
docker run -d --mount ‘src=nginx,dst=/usr/share/nginx/html’ nginx
-
查看挂载信息
- docker inspect nginx -f {{.Mounts}}
-
volume
-
注意
- volume可以先创建再挂载,若未创建挂载时会自动创建
- 若运行容器时不指定volume, docker将为容器创建一个匿名卷挂载
- 如果volume是空的而container中的目录有内容,那么docker会将container目录中的内容拷贝到volume中
- 如果volume中已经有内容,则会将container中的目录覆盖
-
优势
docker网络
查看网络模式
- docker network ls
- Docker安装后,会创建三种网络模式:bridge,host,none
网络模式
-
bridge
-
bridge模式是容器的默认网络模式,相当于vmware中的NAT
-
Docker安装时在宿主机创建虚拟网桥docker0,每开启一个容器,按照顺序从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关,容器连接到虚拟网桥docker0
-
虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中
-
在主机上创建一对虚拟网卡veth pair设备,Docker将veth pair设备的一端放在容器中,命名为eth0(容器的网卡),另一端放在主机中,命名为vethxxx,并将这个网络设备加入到docker0网桥中。可以通过brctl show命令查看
-
结构图
-
host
- 运行容器时使用–network=host指定,容器和宿主机使用同一个网络空间
- 容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口
- 例如,在容器中运行一个Web服务,监听8080端口,则主机的8080端口就会自动映射到容器中
-
none
- 运行容器时使用–network=none指定,容器将没有网络空间
-
container
- 运行容器时使用–net container:NAMES指定,新容器和指定的容器使用同一个网络空间
- docker run -itd --name apache3 --net container:apache1 centos
- container网络不能和 -p|-h 一起使用
-
自定义
-
创建网桥
- docker network create --subnet 192.168.20.0/24 net-20
-
指定容器IP
- docker run -itd --network net-20 --ip 192.168.20.10 centos
-
只有自定义网络支持指定IP,不指定时仍按顺序分配
容器跨主机通信
-
直接路由
- 通过在Docker主机上添加静态路由实现跨宿主机通信
-
pipework
- 一个网络配置脚本,通过ip、brctl、ovs-vsctl等命令来为Docker容器配置自定义的网桥、网卡、路由等
- 使用新建的br0网桥代替缺省的docker0网桥,br0和主机eth0之间是veth pair
- https://github.com/jpetazzo/pipework/blob/master/pipework
-
flannel
- 每个主机上安装并运行etcd和flannel,在etcd中规划配置所有主机的docker0子网范围
- 每个主机上的flanneld根据etcd中的配置,为本主机的docker0分配子网,保证所有主机上的docker0网段不重复,并将结果存入etcd库中,这样etcd库中就保存了所有主机上的docker子网信息和本主机IP的对应关系
- 当需要与其他主机上的容器进行通信时,查找etcd数据库,找到目的容器的子网所对应的outip(目的宿主机的IP)
- 将原始数据包封装在VXLAN或UDP数据包中,IP层以outip为目的IP进行封装
- 由于目的IP是宿主机IP,因此路由是可达的
- VXLAN或UDP数据包到达目的宿主机解封装,解出原始数据包,最终到达目的容器
dockerfile
介绍
FROM
MAINTAINER
RUN
-
语法
-
RUN command arg1 arg2 …
- 由shell启动,类似于直接在命令行输入命令. Linux默认为 /bin/sh -c
-
RUN [“命令”,“arg1”,“arg2”]
-
每一条RUN都会新建立一层(开启一个容器),在其上执行这些命令,执行结束后,commit这一层的修改,构成新的镜像
-
多条命令用命令连接符连接以减少RUN的使用,尽量避免产生不必要的层
-
每一层只保留真正需要的东西,类似于安装包、暂存目录、yum缓存等不必要的东西都建议清理掉
COPY
-
语法
- COPY <源路径>… <目标路径>
- COPY [“<源路径1>”,… “<目标路径>”]
-
将构建上下文目录中<源路径>的文件或目录复制到新的一层的镜像内的<目标路径>位置
-
<源路径>可以是多个,支持通配符
-
<目标路径>可以是绝对路径或相对于工作目录(WORKDIR指令指定)的相对路径,不需提前创建
-
源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等
ADD
-
语法
-
-
-
注意
- ADD指令会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢
- 选择建议:所有的文件复制均使用COPY指令,仅在需要自动解压缩的场合使用ADD
CMD
-
语法
-
用于指定默认的容器主进程的启动命令,运行容器时执行
-
CMD命令可被docker run中的命令覆盖,如果有多个CMD命令,则最后一条生效
-
对于容器而言,其启动程序就是容器应用进程. 容器仅为前台主进程而存在,前台主进程退出,容器就失去了存在的意义,从而退出
-
前台启动
ENTRYPOINT
-
语法
- ENTRYPOINT application “arg1”, “arg2”, …
- ENTRYPOINT [“application”,“arg1”, “arg2”]
-
用于指定默认的容器主进程的启动命令,运行容器时执行
-
ENTRYPOINT命令也可以被覆盖,但docker run需要指定–entrypoint,多个ENTRYPOINT只有最后一个生效
-
结合CMD和ENTRYPOINT,可以从CMD中移除“application”而仅仅保留参数,参数将传递给ENTRYPOINT,也可以从命令行中捕获执行时需要的参数
EXPOSE
ENV
VOLUME
WORKDIR
USER
HEALTHCHECK
-
语法
- HEALTHCHECK [选项] CMD <命令> :设置检查容器健康状况的命令
- HEALTHCHECK NONE :如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令
-
选项
-
interval=<间隔>
-
timeout=<时长>
- 健康检查命令运行超时时间,超过则本次被视为失败,默认 30 秒
-
retries=<次数>
- 当连续失败指定次数后,则将容器状态视为 unhealthy ,默认3次
-
告诉Docker如何判断容器的状态是否正常,1.12 引入,引入前只能通过容器内主进程是否退出来判断
-
如果程序进入死锁或死循环状态,应用进程并不退出但是该容器已经无法提供服务了,1.12前就无法检测到
-
启动容器时的初始状态为starting ,检查成功后变为 healthy ,如果连续一定次数失败,则会变为 unhealthy
-
HEALTHCHECK 只可以出现一次,如果写了多个,只有最后一个生效
练习
-
1
- 基于centos:7镜像构建一个镜像centos7:yum,修改官方yum源为国内镜像源
- [root@docker2 centos-yum]# vim Dockerfile
FROM centos:7
RUN 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
[root@docker2 centos-yum]# docker build -t centos7:yum ./
-
2
- 基于centos7:yum镜像构建一个已安装好apache服务的镜像,要求用此镜像启动容器时,若接-P选项其80端口会映射到宿主机的随机端口,且能正常提供http服务(要有网页), 网页的内容是 Apache is working. Ipaddress is XXX.
- [root@docker2 apache]# vim Dockerfile
FROM centos7:yum
RUN yum install -y httpd && yum clean all
EXPOSE 80
COPY [“entrypoint.sh”,“/usr/local/bin/”]
CMD [“httpd”,“-DFOREGROUND”]
ENTRYPOINT [“entrypoint.sh”]
[root@docker2 apache]# cat entrypoint.sh
#!/bin/bash
echo “Apache is working. Ipaddress is hostname -I
.” > /var/www/html/index.html
exec “$@”
[root@docker2 apache]# chmod +x entrypoint.sh
[root@docker2 apache]# docker build -t apache:v1 ./
-
3
- 基于centos7:yum镜像构建mariadb数据库镜像,要求启动镜像可提供数据库服务,且要求数据能够持久保存在磁盘中
- [root@docker2 mariadb]# vim Dockerfile
FROM centos7:yum
RUN yum -y install mariadb-server && yum clean all
COPY [“entrypoint.sh”,“/usr/local/bin”]
VOLUME [“/var/lib/mysql/”]
CMD [“mysqld_safe”]
ENTRYPOINT [“entrypoint.sh”]
[root@docker2 mariadb]# vim entrypoint.sh
#!/bin/bash
[ -d “/var/lib/mysql/mysql” ] || mysql_install_db --basedir=/usr --datadir=/var/lib/mysql --user=mysql
mysqld_safe &
while :;do
mysql -h localhost -e “grant all on . to ‘
M
Y
S
Q
L
U
S
E
R
′
@
′
MYSQL_USER'@'
MYSQLUSER′@′MYSQL_HOST’ identified by 'KaTeX parse error: Expected 'EOF', got '&' at position 24: …ER_PASSWORD';" &̲& pkill mysql …@”
[root@docker2 mariadb]# chmod +x entrypoint.sh
[root@docker2 mariadb]# docker build -t mariadb:v1 ./
[root@docker2 mariadb]# docker run -d --name mariadb -e MYSQL_USER=user1 -e MYSQL_HOST=172.17.0.1 -e MYSQL_USER_PASSWORD=123 mariadb:v1
[root@docker2 mariadb]# mysql -u user1 -p123 -h 172.17.0.4
-
4
- 基于Alpine镜像构建一个nginx镜像 https://zhuanlan.zhihu.com/p/116084967
- [root@docker2 nginx]# vim Dockerfile
FROM alpine
ADD [“nginx-1.14.0.tar.gz”,“/tmp/”]
RUN echo “https://mirrors.aliyun.com/alpine/v3.6/main/” > /etc/apk/repositories &&
echo “https://mirrors.aliyun.com/alpine/v3.6/community/” >> /etc/apk/repositories &&
apk add gcc g++ pcre-dev make &&
addgroup -S nginx &&
adduser -DSH -s /sbin/nologin -G nginx nginx &&
cd /tmp/nginx-1.14.0 &&
./configure --user=nginx --without-http_gzip_module --sbin-path=/usr/sbin/ &&
make && make install &&
rm -rf /tmp/nginx-1.14.0
EXPOSE 80
CMD [“nginx”,“-g”,“daemon off;”]
[root@docker2 nginx]# docker build -t nginx:v1 ./
多阶段构建
-
介绍
- Docker 17.05版本以后,支持了多阶段构建,即允许一个Dockerfile 中出现多个 FROM 指令
- Docker的镜像内容中,并非只是一个文件,而是有依赖关系的层级结构,后面以前一层为基础, Dockerfile 中的大多数指令都会生成一个层
- 多个 FROM 指令时,最后生成的镜像,以最后一条 FROM 为准,之前的 FROM 会被抛弃
- 在后面的 FROM 指令中, 能够将前面阶段中的文件拷贝到后边的阶段中,这就是多阶段构建的最大意义。最大的使用场景是将编译环境和运行环境分离
-
多阶段构建redis
- FROM centos7:yum
RUN yum install -y gcc gcc-c++ make
ADD [“redis-4.0.10.tar.gz”,“/”]
RUN cd /redis-4.0.10 && make && sed -i ‘/^bind/s/127.0.0.1/0.0.0.0/’ redis.conf
FROM ubuntu
COPY --from=0 [“/redis-4.0.10/src/redis-server”,“/redis-4.0.10/redis.conf”,“/redis/”]
CMD [“/redis/redis-server”,“/redis/redis.conf”]
- redis服务,只需要启动脚本redis-server和配置文件redis.conf即可运行
FROM ubuntu
COPY --from=builder …
- 从镜像
- FROM ubuntu
COPY --from=quay.io/coreos/etcd:v3.3.9 [“/usr/local/bin/etcd”,“/usr/local/bin/”]
- 直接将官方编译好的程序文件拿过来使用
-
例
- 使用多阶段构建一个redis6-alpine镜像的Dockerfile
- FROM alpine
ENV pkg=redis-6.2.7.tar.gz
ENV dl_url=https://download.redis.io/releases/redis-6.2.7.tar.gz
ENV src_dir=redis-6.2.7
RUN sed -i ‘s/dl-cdn.alpinelinux.org/mirrors.aliyun.com/’ /etc/apk/repositories;
apk update;
apk add -t .build-deps gcc libc-dev make linux-headers wget;
wget $dl_url;
tar xf $pkg;
cd $src_dir;
sed -i ‘/^bind/s/127.0.0.1/0.0.0.0/’ redis.conf;
make
FROM alpine
ENV src_dir=redis-6.2.7
COPY --from=0 [“/
s
r
c
d
i
r
/
s
r
c
/
r
e
d
i
s
−
s
e
r
v
e
r
"
,
"
/
src_dir/src/redis-server","/
srcdir/src/redis−server","/src_dir/src/redis-cli”,“/$src_dir/redis.conf”,“/redis/”]
CMD [“/redis/redis-server”,“/redis/redis.conf”]
docker监控
Docker容器的监控
-
容器的基本信息
- 包括容器的数量、ID、名称、镜像、启动命令、端口等信息
-
容器的运行状态
- 统计各状态的容器的数量,包括运行中、暂停、停止及异常退出
-
容器的用量信息
- 统计容器的CPU使用率、内存使用量、块设备I/O使用量、网络使用情况等资源的使用情况
容器的监控方案
docker原理
Namespace
Cgroups
-
对于应用进程来说,namespace实质上只是限制了‘视线’,它使用的资源(cpu、内存等)还是同其他所有进程平等竞争
-
Control Group,最主要作用是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等。此外还能够对进程进行优先级设置、审计,以及将进程挂起和恢复等操作
-
在Linux中,Cgroups给用户暴露出来的操作接口是文件系统,即它以文件和目录的方式组织在/sys/fs/cgroup路径下
-
限制cpu
-
[root@docker ~]# cd /sys/fs/cgroup/
- 该目录下都是当前可以被cgroup进行限制的资源种类
-
[root@docker cgroup]# cd cpu
-
[root@docker cpu]# mkdir cg
-
[root@docker cpu]# cd cg
-
[root@docker cg]# echo 20000 > cpu.cfs_quota_us
- 限制cpu使用率上限为20%(100ms内使用20ms)
-
[root@docker cg]# echo 12411 > tasks
-
docker run -d --name nginx2 --cpu-quota 20000 nginx:v3
-
限制内存
- Cgroups对资源的限制能力也有很多不完善的地方,被提及最多的是/proc文件系统的问题
- /proc目录存储的是记录当前内核运行状态的一系列特殊文件,top, free等指令查看系统信息的主要数据来源
- 通过docker run -itd -m 256m centos:v1限制内存,但是在容器里执行free,仍是宿主机的内存数据
- 原因在/proc文件系统不了解Cgroups限制的存在。解决思路:容器不挂载宿主机的/proc目录
- 实现工具:lxcfs。把宿主机的/var/lib/lxcfs/proc目录下的文件挂载到Docker容器的/proc目录中对应的位置
- [root@docker ~]# vim /etc/yum.repos.d/lxcfs.repo
[lxcfs]
name=lxcfs3
baseurl=https://copr-be.cloud.fedoraproject.org/results/ganto/lxc3/epel-7-x86_64/
enabled=1
gpgcheck=1
gpgkey=https://copr-be.cloud.fedoraproject.org/results/ganto/lxc3/pubkey.gpg
[root@docker ~]# yum install -y lxcfs #安装软件
[root@docker ~]# lxcfs /var/lib/lxcfs/ & #启动服务
[root@docker ~]# docker run -itd --name centos1 -m 256m
-v /var/lib/lxcfs/proc/cpuinfo:/proc/cpuinfo:rw
-v /var/lib/lxcfs/proc/diskstats:/proc/diskstats:rw
-v /var/lib/lxcfs/proc/meminfo:/proc/meminfo:rw
-v /var/lib/lxcfs/proc/stat:/proc/stat:rw
-v /var/lib/lxcfs/proc/swaps:/proc/swaps:rw
-v /var/lib/lxcfs/proc/uptime:/proc/uptime:rw centos:v1
镜像
-
文件系统隔离
- Mount Namespace,一般会在这个容器的根目录下挂载一个完整操作系统的文件系统
- 这个挂载在容器根目录上、用来为容器进程提供隔离后执行环境的文件系统,就是所谓的"容器镜像"
- 它也叫作rootfs(根文件系统),rootfs只是一个操作系统所包含的文件、配置和目录,并不包括操作系统内核。操作系统只有在开机启动时才会加载指定版本的内核镜像
- 由于rootfs里打包的不只是应用,而是整个操作系统的文件和目录,也就意味着,应用以及它运行所需要的所有依赖,都被封装在了一起,这就赋予了容器所谓的一致性
- 为了解决每次操作都需要重复制作一次rootfs问题,Docker在镜像的设计中,引入了层(layer)的概念。即: 用户制作镜像的每一步操作,都生成一个层,也就是一个增量rootfs
-
overlay
-
layer的概念用到了联合文件系统(Union File System)的能力,最主要的功能是将多个不同位置的目录联合挂载(union mount)到同一个目录下
-
文件系统:aufs, device mapper, btrfs, overlayfs, vfs, zfs。ubuntu和centos默认overlayfs
-
OverlayFS将主机上两个不同位置的目录(“层”) 联合挂载到同一目录下,底层的目录叫做lowerdir(镜像层),顶层的目录为upperdir(容器层),对外展示统一视图的目录为merged
-
示意图
-
操作
-
读文件
- 如果容器中有,则读取容器层中的文件;否则读取镜像层中的文件
- 读操作不会改变任何层中的文件
-
写文件
-
创建
-
修改
- 如果容器层有,直接修改容器层中的文件;否则将文件复制到容器层进行修改
-
删除
- 如果镜像层有,在容器层创建标记文件用于隐藏;否则直接删除
-
写文件永远只发生在容器层
-
OverlayFS挂载
- mkdir lower upper work merg
- mount -t overlay -o lowerdir=lower/,upperdir=upper/,workdir=work/ overlay merg/
-
overlay2
容器
docker commit
- 在容器运行起来后,把最上层的"可读写层”"加上原先容器镜像的只读层,打包组成了一个新的镜像
- 由于使用了联合文件系统,在容器里对镜像rootfs所做的任何修改,都会被操作系统先复制到这个可读写层,然后再修改。这个过程,我们称之为:Copy-on-Write
- Init 层的存在,是为了避免执行docker commit时,把Docker自己对/etc/hosts 等文件做的修改也一起提交掉
总结
- 一个"容器",实际上是一个由 Linux Namespace、Linux Cgroups 和 rootfs 三种技术构建出来的进程的隔离环境
- 一个正在运行的 Linux 容器可以分为两部分:
- 一组联合挂载的 rootfs,这一部分我们称为"容器镜像"(Container Image),是容器的静态视图
- 一个由 Namespace+Cgroups 构成的隔离环境,这一部分我们称为"容器运行时"(Container Runtime),是容器的动态视图
docker exec
-
Namespace信息在宿主机上是以一个文件的方式存在:/proc/进程号/ns
-
[root@docker ~]# docker inspect -f {{.State.Pid}} nginx
1901
-
[root@docker ~]# ls -l /proc/1901/ns
-
一个进程,可以选择加入到某个进程已有的Namespace当中,从而达到 “进入” 这个进程所在容器的目的,这正是docker exec的实现原理。这个操作所依赖的,乃是一个名叫 setns() 的 Linux 系统调用
-
docker网络中讲到的的container网络就是将一个容器加入到另一个容器的Network Namespace
volume
-
容器进程
- Docker创建的一个容器初始化进程(dockerinit),负责完成根目录的准备、挂载设备和目录、配置 hostname等一系列需要在容器内进行的初始化操作。最后通过execv()系统调用,让应用进程取代自己,成为容器里的PID=1的进程
-
当容器进程被创建之后,尽管开启了Mount Namespace,但是在它执行chroot之前,容器进程一直可以看到宿主机上的整个文件系统,包括容器镜像
-
镜像的各个层保存在/var/lib/docker/overlay2下,在容器进程启动时,它们会被联合挂载,容器所需的rootfs就准备好了
-
所以只需要在rootfs准备好之后,在执行chroot之前,把Volume指定的宿主机目录(假设/home),挂载到指定的容器目录(假设/test)在宿主机上对应的目录(即/var/lib/docker/overlay2/[读写层 ID]/diff/test)上,这个Volume的挂载工作就完成了
-
由于执行这个挂载操作时,"容器进程”"经创建了,也就意味着此时 Mount Namespace 已经开启了。所以,这个挂载事件只在这个容器里可见。你在宿主机上,是看不见容器内部的这个挂载点的。这就保证了容器的隔离性不会被 Volume 打破
-
bind mount
- mount --bind /home /test
- Linux的绑定挂载机制。允许将一个目录或者文件,而不是整个设备,挂载到一个指定的目录上。此时在该挂载点上进行的任何操作,仅发生在被挂载的目录或者文件上,原挂载点的内容则会被隐藏起来且不受影响
- 绑定挂载实际上是一个inode替换的过程,挂载时将/test的inode替换为/home的inode,umount时还原
-
容器的镜像操作,比如 docker commit,都是发生在宿主机空间的。而由于 Mount Namespace 的隔离作用,宿主机并不知道这个绑定挂载的存在。所以,在宿主机看来,容器中可读写层的 /test 目录始终是空的
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)