走进 Docker 的世界
走进 Docker 的世界
介绍docker的前世今生,了解docker的实现原理,以Django项目为例编写最佳的Dockerfile构建镜像。学习docker的概念及基本操作并构建业务镜像,通过抓包的方式掌握Docker最常用的bridge网络模式的通信。
认识docker
怎么出现的
- 提供轻量、高效的虚拟化能力
Docker 公司位于旧金山,原名dotCloud,底层利用了Linux容器技术(LXC)(在操作系统中实现资源隔离与限制)。为了方便创建和管理这些容器,dotCloud 开发了一套内部工具,之后被命名为“Docker”。Docker就是这样诞生的。

Hypervisor: 一种运行在基础物理服务器和操作系统之间的中间软件层,可允许多个操作系统和应用共享硬件 。常见的VMware的 Workstation 、ESXi、微软的Hyper-V或者思杰的XenServer。
Container Runtime:通过Linux内核虚拟化能力管理多个容器,多个容器共享一套操作系统内核。因此摘掉了内核占用的空间及运行所需要的耗时,使得容器极其轻量与快速。
- 软件交付过程中的环境依赖

几个知识点
- 可以把应用程序代码及运行依赖环境打包成镜像,作为交付介质,在各环境部署
- 可以将镜像(image)启动成为容器(container),并且提供多容器的生命周期进行管理(启、停、删)
- container容器之间相互隔离,且每个容器可以设置资源限额
- 提供轻量级虚拟化功能,容器就是在宿主机中的一个个的虚拟的空间,彼此相互隔离,完全独立
- CS架构的软件产品

版本管理
-
Docker 引擎主要有两个版本:企业版(EE)和社区版(CE)
-
每个季度(1-3,4-6,7-9,10-12),企业版和社区版都会发布一个稳定版本(Stable)。社区版本会提供 4 个月的支持,而企业版本会提供 12 个月的支持
-
每个月社区版还会通过 Edge 方式发布月度版
-
从 2017 年第一季度开始,Docker 版本号遵循 YY.MM-xx 格式,类似于 Ubuntu 等项目。例如,2018 年 6 月第一次发布的社区版本为 18.06.0-ce

发展史
13年成立,15年开始,迎来了飞速发展。

Docker 1.8之前,使用LXC,Docker在上层做了封装, 把LXC复杂的容器创建与使用方式简化为自己的一套命令体系。
之后,为了实现跨平台等复杂的场景,Docker抽出了libcontainer项目,把对namespace、cgroup的操作封装在libcontainer项目里,支持不同的平台类型。
2015年6月,Docker牵头成立了 OCI(Open Container Initiative开放容器计划)组织,这个组织的目的是建立起一个围绕容器的通用标准 。 容器格式标准是一种不受上层结构绑定的协议,即不限于某种特定操作系统、硬件、CPU架构、公有云等 , 允许任何人在遵循该标准的情况下开发应用容器技术,这使得容器技术有了一个更广阔的发展空间。
OCI成立后,libcontainer 交给OCI组织来维护,但是libcontainer中只包含了与kernel交互的库,因此基于libcontainer项目,后面又加入了一个CLI工具,并且项目改名为runC (https://github.com/opencontainers/runc ), 目前runC已经成为一个功能强大的runtime工具。
Docker也做了架构调整。将容器运行时相关的程序从docker daemon剥离出来,形成了containerd。containerd向上为Docker Daemon提供了gRPC接口,使得Docker Daemon屏蔽下面的结构变化,确保原有接口向下兼容。向下通过containerd-shim结合runC,使得引擎可以独立升级,避免之前Docker Daemon升级会导致所有容器不可用的问题。

也就是说
-
runC(libcontainer)是符合OCI标准的一个实现,与底层系统交互
-
containerd是实现了OCI之上的容器的高级功能,比如镜像管理、容器执行的调用等
-
Dockerd目前是最上层与CLI交互的进程,接收cli的请求并与containerd协作
小结
1、为了解决软件交付过程中的环境依赖,同时提供一种更加轻量的虚拟化技术,Docker出现了
2、Docker是一种CS架构的软件产品,可以把代码及依赖打包成镜像,作为交付介质,并且把镜像启动成为容器,提供容器生命周期的管理
3、docker-ce,每季度发布stable版本。20.03,20.06,20.09
4、发展至今,docker已经通过制定OCI标准对最初的项目做了拆分,其中runC和containerd是docker的核心项目,理解docker整个请求的流程,对深入理解docker有很大的帮助
安装
配置宿主机网卡转发
## 若未配置,需要执行如下
$ cat <<EOF > /etc/sysctl.d/docker.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward=1
EOF
$ sysctl -p /etc/sysctl.d/docker.conf

Yum 安装配置docker
## 下载阿里源repo文件
$ curl -o /etc/yum.repos.d/Centos-7.repo http://mirrors.aliyun.com/repo/Centos-7.repo
$ curl -o /etc/yum.repos.d/docker-ce.repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
$ yum clean all && yum makecache
## yum安装
$ yum install docker-ce -y
## 查看源中可用版本
$ yum list docker-ce --showduplicates | sort -r
## 安装指定版本
##yum install -y docker-ce-18.09.9
## 配置源加速
## https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors
mkdir -p /etc/docker
vi /etc/docker/daemon.json
{
"registry-mirrors" : [
"https://9ai55q0c.mirror.aliyuncs.com"
]
}
## 设置开机自启
systemctl enable docker
systemctl daemon-reload
## 启动docker
systemctl start docker
## 查看docker信息
docker info
## docker-client
which docker
## docker daemon
ps aux |grep docker
## containerd
ps aux|grep containerd
systemctl status containerd
核心要素及常用操作详解

三大核心要素:镜像(Image)、容器(Container)、仓库(Registry)
镜像(Image)
打包了业务代码及运行环境的包,是静态的文件,不能直接对外提供服务。
容器(Container)
镜像的运行时,可以对外提供服务。
仓库(Registry)
存放镜像的地方
-
公有仓库,Docker Hub,阿里,网易...
-
私有仓库,私人及企业内部搭建
- Docker Registry,Docker官方提供的镜像仓库存储服务
- Harbor, 是Docker Registry的更高级封装,它提供友好的Web UI界面,角色和用户权限管理,用户操作审计等功能
-
镜像访问地址形式 registry.devops.com/demo/hello:latest,若没有前面的url地址,则默认寻找Docker Hub中的镜像,若没有tag标签,则使用latest作为标签。 比如,docker pull nginx,会被解析成docker.io/library/nginx:latest
-
公有的仓库中,一般存在这么几类镜像
- 操作系统基础镜像(centos,ubuntu,suse,alpine)
- 中间件(nginx,redis,mysql,tomcat)
- 语言编译环境(python,java,golang)
- 业务镜像(django-demo...)
容器和仓库不会直接交互,都是以镜像为载体来操作。
1.查看镜像列表
$ docker images
2.如何获取镜像
-
从远程仓库拉取
$ docker pull nginx:alpine $ docker images -
本地构建
$ docker build . -t my-nginx:ubuntu -f Dockerfile
3.如何通过镜像启动容器
# --name 是自定义的名称
$ docker run --name my-nginx-alpine -d nginx:alpine
4.如何知道容器内部运行了什么程序?
# 进入容器内部,分配一个tty终端
$ docker exec -ti my-nginx-alpine /bin/sh
# ps aux
5.docker怎么知道容器启动后该执行什么命令?
通过docker build来模拟构建一个nginx的镜像
-
创建Dockerfile
# 告诉docker使用哪个基础镜像作为模板,后续命令都以这个镜像为基础 FROM ubuntu # RUN命令会在上面指定的镜像里执行命令 RUN apt-get update && apt install -y nginx #告诉docker,启动容器时执行如下命令 CMD ["/usr/sbin/nginx", "-g","daemon off;"] -
构建本地镜像
$ docker build . -t my-nginx:ubuntu -f Dockerfile

-
使用新镜像启动容器
$ docker run --name my-nginx-ubuntu -d my-nginx:ubuntu -
进入容器查看进程
$ docker exec -ti my-nginx-ubuntu /bin/sh # ps aux

6.如何访问容器内服务
# 进入容器内部
$ docker exec -ti my-nginx-alpine /bin/sh
# ps aux|grep nginx
# curl localhost:80
7.宿主机中如何访问容器服务
# 删掉旧服务,重新启动
$ docker rm -f my-nginx-alpine
$ docker run --name my-nginx-alpine -d -p 8080:80 nginx:alpine
$ curl 10.2.2.10:8080

操作演示

1.查看所有镜像:
$ docker images
2.拉取镜像:
$ docker pull nginx:alpine
3.如何唯一确定镜像:
- image_id
- repository:tag
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
my-nginx ubuntu 33fed20f1cdd 2 hours ago 156MB
ubuntu latest 4e2eef94cd6b 3 weeks ago 73.9MB
nginx alpine 6f715d38cfe0 4 weeks ago 22.1MB
4.导出镜像到文件中
$ docker save -o nginx.alpine.tar nginx:alpine
$ ll
total 23040
-rw-r--r-- 1 root root 99 Sep 11 10:03 Dockerfile
-rw------- 1 root root 23586816 Sep 12 08:13 nginx.alpine.tar
5.从文件中加载镜像
$ docker load -i nginx-alpine.tar
6.部署镜像仓库
https://docs.docker.com/registry/
## 使用docker镜像启动镜像仓库服务
$ docker run -d -p 5000:5000 --restart always --name registry registry:2
## 默认仓库不带认证,若需要认证,参考
https://docs.docker.com/registry/deploying/#restricting-access
7.推送本地镜像到镜像仓库中
## 给镜像打上标签
$ docker tag nginx:alpine localhost:5000/nginx:alpine
$ docker push localhost:5000/nginx:alpine
## 镜像仓库给外部访问,不能通过localhost,尝试使用内网地址10.2.2.10:5000/nginx:alpine
$ docker tag nginx:alpine 10.2.2.10:5000/nginx:alpine
$ docker push 10.2.2.10:5000/nginx:alpine
The push refers to repository [10.2.2.10:5000/nginx]
## docker默认不允许向http的仓库地址推送,如何做成https的,参考:https://docs.docker.com/registry/deploying/#run-an-externally-accessible-registry
## 至此没有可信证书机构颁发的证书和域名,自签名证书需要在每个节点中拷贝证书文件,比较麻烦,因此通过配置daemon的方式,来跳过证书的验证:
$ cat /etc/docker/daemon.json
{
"registry-mirrors" : [
"https://8xpk5wnt.mirror.aliyuncs.com"
],
"insecure-registries": [
"10.2.2.10:5000"
]
}
$ systemctl restart docker # 要重启docker
$ docker push 10.2.2.10:5000/nginx:alpine'
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
my-nginx ubuntu 33fed20f1cdd 3 hours ago 156MB
ubuntu latest 4e2eef94cd6b 3 weeks ago 73.9MB
10.2.2.10:5000/nginx alpine 6f715d38cfe0 4 weeks ago 22.1MB
nginx alpine 6f715d38cfe0 4 weeks ago 22.1MB
localhost:5000/nginx alpine 6f715d38cfe0 4 weeks ago 22.1MB
registry 2 2d4f4b5309b1 2 months ago 26.2MB
8.删除镜像
$ docker rmi nginx:alpine
9.查看容器列表
## 查看运行状态的容器列表
$ docker ps
## 查看全部状态的容器列表
$ docker ps -a
10.启动容器
## 后台启动
$ docker run --name nginx -d nginx:alpine
## 映射端口,把容器的端口映射到宿主机中,-p <host_port>:<container_port>
$ docker run --name nginx -d -p 8080:80 nginx:alpine
## 资源限制,最大可用内存500M
$ docker run --memory=500m nginx:alpine
11.容器数据持久化
## 挂载主机目录
$ docker run --name nginx -d -v /opt/:/opt -v /var/log:/var/log nginx:alpine
$ docker run --name mysql -e MYSQL_ROOT_PASSWORD=123456 -d -v /opt/mysql:/var/lib/mysql mysql:5.7
## 使用volumes卷
$ docker volume ls
$ docker volume create my-vol
$ docker run --name nginx2 -d -v my-volume:/opt/my-volume nginx:alpine
$ docker exec -ti nginx2 touch /opt/my-volume/a.txt
## 验证数据共享
$ docker run --name nginx-test -d -v my-volume:/opt/test nginx:alpine
$ docker exec -ti nginx-test ls /opt/test/
a.txt

12.进入容器或者执行容器内的命令
$ docker exec -ti <container_id_or_name> /bin/sh
$ docker exec <container_id_or_name> hostname
13.主机与容器之间拷贝数据
## 主机拷贝到容器
$ echo '123' > /tmp/test.txt
$ docker cp /tmp/test.txt nginx2:/tmp
$ docker exec -ti nginx2 cat /tmp/test.txt
123
## 容器拷贝到主机
docker cp nginx2:/tmp/test.txt ./

14.挂载已有的数据,重新创建镜像仓库容器
## 解压离线镜像文件
$ tar zxf registry.tar.gz -C /opt
## 删除当前镜像仓库容器
$ docker rm -f registry
## 使用docker镜像启动镜像仓库服务, --restart always 是docker每次重启容器随之自启动
$ docker run -d -p 5000:5000 --restart always -v /opt/registry:/var/lib/registry --name registry registry:2
## 查看本地registry 仓库所有镜像
$ curl -XGET http://10.2.2.50:5000/v2/_catalog
## 依据镜像名称查询镜像版本
$ curl -XGET http://10.2.2.50:5000/v2/nginx/tags/list
假设启动镜像仓库服务的主机地址为10.2.2.10,该目录中已存在的镜像列表(仓库镜像已分享):
链接:https://pan.baidu.com/s/19bA2f0aUjYzpZDQLczvYKw
提取码:rnb4
| 现镜像仓库地址 | 原镜像仓库地址 |
|---|---|
| 10.2.2.10:5000/coreos/flannel:v0.11.0-amd64 | quay.io/coreos/flannel:v0.11.0-amd64 |
| 10.2.2.10:5000/mysql:5.7 | mysql:5.7 |
| 10.2.2.10:5000/nginx:alpine | nginx:alpine |
| 10.2.2.10:5000/centos:centos7.5.1804 | centos:centos7.5.1804 |
| 10.2.2.10:5000/elasticsearch/elasticsearch:7.4.2 | docker.elastic.co/elasticsearch/elasticsearch:7.4.2 |
| 10.2.2.10:5000/fluentd-es-root:v1.6.2-1.0 | quay.io/fluentd_elasticsearch/fluentd:v2.5.2 |
| 10.2.2.10:5000/kibana/kibana:7.4.2 | docker.elastic.co/kibana/kibana:7.4.2 |
| 10.2.2.10:5000/kubernetesui/dashboard:v2.0.0-beta5 | kubernetesui/dashboard:v2.0.0-beta5 |
| 10.2.2.10:5000/kubernetesui/metrics-scraper:v1.0.1 | kubernetesui/metrics-scraper:v1.0.1 |
| 10.2.2.10:5000/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0 | quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0 |
| 10.2.2.10:5000/jenkinsci/blueocean:latest | jenkinsci/blueocean:latest |
| 10.2.2.10:5000/sonarqube:7.9-community | sonarqube:7.9-community |
| 10.2.2.10:5000/postgres:11.4 | postgres:11.4 |
15.查看容器日志
## 查看全部日志
$ docker logs nginx
## 实时查看最新日志
$ docker logs -f nginx
## 从最新的100条开始查看
$ docker logs --tail=100 -f nginx
16.停止或者删除容器
## 停止运行中的容器
$ docker stop nginx
## 启动退出容器
$ docker start nginx
## 删除非运行中状态的容器
$ docker rm nginx
## 删除运行中的容器, -f 强制删除
$ docker rm -f nginx
17.查看容器或者镜像的明细
## 查看容器详细信息,包括容器IP地址等
$ docker inspect nginx
## 查看镜像的明细信息
$ docker inspect nginx:alpine
通过1号进程理解容器的本质
docker exec -ti my-nginx-alpine /bin/sh
/ # ps aux
PID USER TIME COMMAND
1 root 0:00 nginx: master process nginx -g daemon off;
30 nginx 0:00 nginx: worker process
31 nginx 0:00 nginx: worker process
32 nginx 0:00 nginx: worker process
33 nginx 0:00 nginx: worker process
34 root 0:00 /bin/sh
39 root 0:00 ps aux
容器启动的时候可以通过命令去覆盖默认的CMD
$ docker run -d --name xxx nginx:alpine <自定义命令>
# <自定义命令>会覆盖镜像中指定的CMD指令,作为容器的1号进程启动
$ docker run -d --name test-3 nginx:alpine echo 123
123
$ docker run -d --name nginx4 nginx:alpine ping www.baidu.com
本质上讲容器是利用namespace和cgroup等技术在宿主机中创建的独立的虚拟空间,这个空间内的网络、进程、挂载等资源都是隔离的
$ docker exec -ti my-nginx /bin/sh
#/ ip addr
#/ ls -l /
#/ apt install xxx
#/ #安装的软件对宿主机和其他容器没有任何影响,和虚拟机不同的是,容器间共享一个内核,所以容器内没法升级内核

浙公网安备 33010602011771号