本文本来是公司部门内部的技术分享,比较基础,特地再整理出来分享给大家。
第一章 容器技术前瞻
1.1 为什么要学习容器:
-
技术新名词层出不穷:
CI/CD
,DevOps
,微服务,云原生,Service Mesh
...... -
容器技术持续火爆:下图显示了2013-2017年从
DockerHub
上下载镜像的次数:
- 云原生生态圈不断完善:(https://landscape.cncf.io/)
1.2 使用容器的优点:
-
快速,一致地交付您的应用程序;
Docker
允许开发人员使用您提供的应用程序或服务的本地容器在标准化环境中工作,从而简化了开发的生命周期。Docker的创始人Solomon Hykes说过“你在Python2.7下测试,线上却运行着Python3,奇怪的事情就发生了;或者你依赖具体某个SSL版本的功能,但服务器上却安装着另外版本的SSL;你在Debian系统上进行了测试,生产环境却是Red Hat,那各种各样的奇怪的事情就会发生。”
容器非常适合持续集成和持续交付(
CI / CD
)工作流程,请考虑以下示例方案:- 您的开发人员在本地编写代码,并使用 Docker 容器与同事共享他们的工作。
- 他们使用
Docker
将其应用程序推送到测试环境中,并执行自动或手动测试。 - 当开发人员发现错误时,他们可以在开发环境中对其进行修复,然后将其重新部署到测试环境中,以进行测试和验证。
- 测试完成后,将修补程序推送给生产环境,就像将更新的镜像推送到生产环境一样简单。
-
响应式部署和扩展;
Docker
是基于容器的平台,允许高度可移植的工作负载。Docker
容器可以在开发人员的本机上,数据中心的物理或虚拟机上,云服务上或混合环境中运行。Docker
的可移植性和轻量级的特性,还可以使您轻松地完成动态管理的工作负担,并根据业务需求指示,实时扩展或拆除应用程序和服务。
- 在同一硬件上运行更多工作负载;
Docker
轻巧快速。它为基于虚拟机管理程序的虚拟机提供了可行、经济、高效的替代方案,因此您可以利用更多的计算能力来实现业务目标。Docker
非常适合于高密度环境以及中小型部署,而您可以用更少的资源做更多的事情。
第二章 容器技术的发展
2.1 容器与主机级虚拟化:
容器技术本身也是虚拟化的一种,只不过比起主机级虚拟化更轻量,每个容器不单独拥有操作系统,而是与宿主机共用内核。
对比传统虚拟机总结:
特性 | 容器 | 虚拟机 |
---|---|---|
启动 | 秒级 | 分钟级 |
硬盘使用 | 一般为 MB
|
一般为 GB
|
性能 | 接近原生 | 弱于 |
系统支持量 | 单机支持上千个容器 | 一般几十个 |
2.2 LXC:
<img src="http://cerberus43-md.oss-cn-beijing.aliyuncs.com/md/2020-04-22-083804.jpg" style="zoom: 150%;" />
LXC
(LinuX Containers)Linux
容器,一种操作系统层虚拟化技术,为Linux
内核容器功能的一个用户空间接口。它将应用软件系统打包成一个软件容器(Container),内含应用软件本身的代码,以及所需要的操作系统核心和库。透过统一的名字空间和共享API来分配不同软件容器的可用硬件资源,创造出应用程序的独立沙箱运行环境,使得Linux
用户可以容易的创建和管理系统或应用容器。
在Linux
内核中,提供了cgroups
功能,来达成资源的隔离(做资源限制)。它同时也提供了名称空间(NameSpaces
)隔离的功能,使应用程序看到的操作系统环境被区隔成独立区间,包括进程树,网络,用户id,以及挂载的文件系统。(ipc, network, user, pid, mount)。
LXC
利用cgroups
与NameSpaces
的功能,提供应用软件一个独立的操作系统环境。LXC
不需要Hypervisor
这个软件层,软件容器(Container)本身极为轻量化,提升了创建虚拟机的速度。
而Docker本质来说不是容器,而是容器的管理工具,最初的Docker也是基于LXC实现的。
第三章 Docker介绍
3.1 Docker简介:
Docker
的英文翻译是“搬运工”的意思,他搬运的东西就是我们常说的集装箱Container
,Container
里面装的是任意类型的 App,我们的开发人员可以通过 Docker
将App 变成一种标准化的、可移植的、自管理的组件,我们可以在任何主流的操作系统中开发、调试和运行。
Docker
最初是 dotCloud
公司创始人 Solomon Hykes 在法国期间发起的一个公司内部项目,它是基于 dotCloud
公司多年云服务技术的一次革新,并于 2013 年 3 月以 Apache 2.0 授权协议开源,主要项目代码在 GitHub 上进行维护。Docker
项目后来还加入了 Linux 基金会,并成立推动 开放容器联盟(OCI)。
Docker
自开源后受到广泛的关注和讨论,至今其 GitHub 项目 已经超过 5 万 4 千个星标和一万多个 fork
。甚至由于 Docker
项目的火爆,在 2013
年底,dotCloud 公司决定改名为 Docker。Docker
最初是在 Ubuntu 12.04
上开发实现的;Red Hat
则从 RHEL 6.5
开始对 Docker
进行支持;Google
也在其 PaaS
产品中广泛应用 Docker
。
Docker
使用 Google
公司推出的 Go 语言 进行开发实现,基于 Linux
内核的 cgroup,namespace,以及 OverlayFS 类的 Union FS 等技术,对进程进行封装隔离,属于 操作系统层面的虚拟化技术。由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。最初实现是基于 LXC,从 0.7 版本以后开始去除 LXC
,转而使用自行开发的 libcontainer,从 1.11 开始,则进一步演进为使用 runC 和 containerd。
Docker Engine
是一个C/S架构的应用程序,主要包含下面几个组件:
- 常驻后台进程
Dockerd
- 一个用来和
Dockerd
交互的 REST API Server - 命令行
CLI
接口,通过和 REST API 进行交互(我们经常使用的 docker 命令)
3.2 Docker安装:
官方安装文档:https://docs.docker.com/get-docker/
-
添加yum源:
yum install epel-release –y yum clean all yum list
-
安装docker-io:
yum install docker-io –y systemctl start docker
-
检查安装结果:
docker info
因国内访问DockerHub仓库比较慢,可以添加阿里云镜像加速配置。阿里云官方镜像加速
3.3 第一个容器:
#运行centos 6.7容器
docker run -it --rm --name=demo01 centos:6.7 /bin/bash
#当看到提示符改变时代表着我们已进入容器内部
#cat /etc/redhat-release
CentOS release 6.7 (Final)
#uname -r
3.10.0-957.12.2.el7.x86_64
#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:7 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:613 (613.0 b) TX bytes:0 (0.0 b)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
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)
#hostname
ecb2a387e9c6
#ps axu
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.1 0.0 11488 1780 pts/0 Ss 07:06 0:00 /bin/bash
root 18 0.0 0.0 13372 1044 pts/0 R+ 07:08 0:00 ps axu
-
Docker Daemon
:dockerd
,用来监听Docker API
的请求和管理Docker
对象,比如镜像、容器、网络和 Volume。 -
Docker Client
:docker
,docker client
是我们和Docker
进行交互的最主要的方式方法,比如我们可以通过 docker run 命令来运行一个容器,然后我们的这个client
会把命令发送给上面的Dockerd
,让他来做真正事情。 -
Images
:镜像,镜像是一个只读模板,带有创建Docker
容器的说明,一般来说的,镜像会基于另外的一些基础镜像并加上一些额外的自定义功能。比如,你可以构建一个基于Centos
的镜像,然后在这个基础镜像上面安装一个Nginx
服务器,这样就可以构成一个属于我们自己的镜像了。 -
Containers
:容器,容器是一个镜像的可运行的实例,可以使用Docker REST API
或者CLI
来操作容器,容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的命名空间。因此容器可以拥有自己的 root 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。 -
Docker Registry
:用来存储Docker
镜像的仓库,Docker Hub
是Docker
官方提供的一个公共仓库,而且Docker
默认也是从Docker Hub
上查找镜像的,当然你也可以很方便的运行一个私有仓库,当我们使用 docker pull 或者 docker run 命令时,就会从我们配置的Docker
镜像仓库中去拉取镜像,使用 docker push 命令时,会将我们构建的镜像推送到对应的镜像仓库中。
底层技术支持:Namespaces(做隔离)、CGroups(做资源限制)、UnionFS(镜像和容器的分层)
第四章 Docker镜像
关键词:“分层构建,联合挂载”,“写时复制”
4.1 镜像的概念:
我们都知道,操作系统分为内核和用户空间。对于 Linux
而言,内核启动后,会挂载 root
文件系统为其提供用户空间支持。而 Docker
镜像(Image),就相当于是一个 root
文件系统。比如官方镜像 ubuntu:18.04
就包含了完整的一套 Ubuntu 18.04
最小系统的 root
文件系统。
Docker
镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。
4.2 镜像常用操作命令:
#查看本地镜像
docker image ls
#查找DockerHub上的镜像
docker search centos
-----
#docker pull [选项] [Docker Registry 地址[:端口]/]仓库名[:标签]
#从DockerHub获取centos 6.7的镜像(DockerHub默认仓库为library)
docker image pull centos:6.7
#从私有镜像仓库获取centos 6.6的镜像
docker image pull 10.1.129.123:81/base_image/centos:6.6
-----
#删除镜像
docker image rm centos:6.7
#描述centos:6.7镜像的详细信息
docker image inspect centos:6.7
#Layers处参数可以看出此镜像只有一层
docker image inspect nginx
#可以看出nginx镜像有三层
#查看centos:6.7镜像的历史
docker image history centos:6.7
4.3 使用Docker Commit定制镜像:
镜像是容器的基础,每次执行docker run
的时候都会指定哪个镜像作为容器运行的基础。在之前的例子中,我们所使用的都是来自于 Docker Hub 的镜像。直接使用这些镜像是可以满足一定的需求,而当这些镜像无法直接满足需求时,我们就需要定制这些镜像。
现在我们以定制一个 Web 服务器为例子,来讲解镜像是如何构建的。
docker run --name webserver1 -d -p 80:80 nginx
这条命令会用 nginx 镜像启动一个容器,命名为 webserver,并且映射了 80 端口,这样我们可以用浏览器去访问http://10.1.129.122/这个 nginx 服务器,会看到默认的 Nginx 欢迎页面。
但是如果我们不喜欢这个欢迎页面,希望改成欢迎 Docker 的文字,我们就可以使用 docker exec命令进入容器,修改其内容。
docker exec -it webserver1 bash
#修改默认欢迎页面
echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
刷新下页面,就可以看到Hello,Docker!
我们修改了容器的文件,也就是改动了容器的存储层。我们可以通过docker diff
命令看到具体的改动。
docker diff fccd0bf45940
C /run
A /run/nginx.pid
C /var
C /var/cache
C /var/cache/nginx
A /var/cache/nginx/proxy_temp
A /var/cache/nginx/scgi_temp
A /var/cache/nginx/uwsgi_temp
A /var/cache/nginx/client_temp
A /var/cache/nginx/fastcgi_temp
C /usr
C /usr/share
C /usr/share/nginx
C /usr/share/nginx/html
C /usr/share/nginx/html/index.html
当我们运行一个容器的时候(如果不使用卷的话),我们做的任何文件修改都会被记录于容器存储层里。而 Docker 提供了一个docker commit
命令,可以将容器的存储层保存下来成为镜像。换句话说,就是在原有镜像的基础上,再叠加上容器的存储层,并构成新的镜像。以后我们运行这个新镜像的时候,就会拥有原有容器最后的文件变化。
我们可以用下面的命令将容器保存为镜像:
docker commit \
--message "修改默认页面" \
webserver1 \
nginx-demo:v1
使用docker image ls查看刚才commit的镜像;
也可以使用docker image history
查看镜像历史:
docker image history nginx-demo:v1
docker commit
命令除了学习之外,还有一些特殊的应用场合,比如被入侵后保存现场等。但是,不要使用 docker commit
定制镜像,定制镜像应该使用Dockerfile
来完成。
4.4 使用Dockerfile定制镜像:
我们还是以刚才的webserver为例子:
FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
-
FROM 指定基础镜像:
所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制。就像我们之前运行了一个 nginx 镜像的容器,再进行修改一样,基础镜像是必须指定的。而 FROM 就是指定基础镜像,因此一个 Dockerfile 中 FROM 是必备的指令,并且必须是第一条指令。
在 Docker Hub 上有非常多的高质量的官方镜像,有可以直接拿来使用的服务类的镜像,如 nginx、redis、mongo、mysql、httpd、php、tomcat 等;也有一些方便开发、构建、运行各种语言应用的镜像,如 node、openjdk、python、ruby、golang 等。可以在其中寻找一个最符合我们最终目标的镜像为基础镜像进行定制。
如果没有找到对应服务的镜像,官方镜像中还提供了一些更为基础的操作系统镜像,如 ubuntu、debian、centos、fedora、alpine 等,这些操作系统的软件库为我们提供了更广阔的扩展空间。
除了选择现有镜像为基础镜像外,Docker 还存在一个特殊的镜像,名为 scratch。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。 -
RUN 执行命令:
RUN
指令是用来执行命令行命令的。由于命令行的强大能力,RUN
指令在定制镜像时是最常用的指令之一。其格式有两种:-
shell 格式:
RUN <命令>
,就像直接在命令行中输入的命令一样。刚才写的 Dockerfile 中的RUN
指令就是这种格式。RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
-
exec 格式:
RUN ["可执行文件", "参数1", "参数2"]
,这更像是函数调用中的格式。
-
使用docker build构建:
docker build -t nginx-demo:v2 .
docker run -d -p 80:81 --name webserver2 nginx-demo:v2
4.5 理解镜像的构成原理:
使用docker image inspect
对比下 nginx-demo:v2
与 nginx:latest
镜像,会发现多了一层:
docker image inspect nginx-demo:v2
docker image inspect nginx
镜像是多层存储,每一层是在前一层的基础上进行的修改;而容器同样也是多层存储,是在以镜像为基础层,在其基础上加一层作为容器运行时的存储层。
- ”写时复制“特性:
当 Docker 第一次启动一个容器时,初始的读写层是空的,当文件系统发生变化时,这些变化都会应用到这一层 之上。比如,如果想修改一个文件,这个文件首先会从该读写层下面的只读层复制到该读写层。由此,该文件的只读版本依然存在于只读层,只是被读写层的该文件副本所隐藏。该机制则被称之为写时复制(Copy on write)。
第五章 Docker容器
对于运维来说,容器与镜像的关系就像虚拟机与模板。对于开发来说,容器与镜像的关系就像类与实例。
<img src="http://cerberus43-md.oss-cn-beijing.aliyuncs.com/md/2020-04-23-091849.jpg" style="zoom:200%;" />
5.1 容器常用操作命令:
#运行centos 6.7容器并打开一个交互终端
docker run -it centos:6.7
#查看运行中的容器
docker container ps
#运行centos 6.7容器,打开一个交互终端,默认进去命令为/bin/bash,命名为centos6.7,并在退出后删除
docker run -it --rm --name=centos6.7 centos:6.7 /bin/bash
#查看所有容器(包括停止的)
docker container ps -a
#进入id为177bb3ef28fe的容器
docker exec -it 177bb3ef28fe /bin/bash
#停止id为177bb3ef28fe的容器
docker stop 177bb3ef28fe
#删除id为177bb3ef28fe的容器
docker rm 177bb3ef28fe
关于后台运行:
#后台运行centos 6.7容器
docker run -d centos:6.7
docker ps -a 查看容器已经停止了,因为默认的centos 6.7镜像的命令是/bin/bash,命令执行完了,容器也就退出了
#后台运行centos 6.7容器,并运行shell命令 sleep 3600
docker run -d centos:6.7 sleep 3600
容器是否会长久运行,是和 docker run 指定的命令有关,和 -d 参数无关!
容器是否会长久运行,是和 docker run 指定的命令有关,和 -d 参数无关!
容器是否会长久运行,是和 docker run 指定的命令有关,和 -d 参数无关!
5.2 容器存储与持久化:
-
挂载主机目录作为数据卷:
使用
--mount
标记可以指定挂载一个本地主机的目录到容器中去:docker run -d -p 80:80 \ --name webserver3 \ --mount type=bind,source=/data/demo/nginx-demo-v3,target=/var/log/nginx \ nginx
上面的命令把宿主机的/data/demo/nginx-demo-v3目录挂载到容器的/var/log/nginx目录中(也就是nginx的log目录)
tail -f /data/demo/nginx-demo-v3/access.log
-
使用数据卷:
数据卷 是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,可以提供很多有用的特性:
- 数据卷` 可以在容器之间共享和重用;
-
对 数据卷 的修改会立马生效;
- 对 数据卷的更新,不会影响镜像;
-
数据卷默认会一直存在,即使容器被删除;
注意:数据卷 的使用,类似于 Linux 下对目录或文件进行 mount,镜像中的被指定为挂载点的目录中的文件会隐藏掉,能显示看的是挂载的 数据卷。
创建一个数据卷:
docker volume create nginx-demo-v4
查看所有的数据卷:
docker volume ls
查看指定 数据卷 的信息:
docker volume inspect nginx-demo-v4
[
{
"CreatedAt": "2020-05-11T17:25:56+08:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/nginx-demo-v4/_data",
"Name": "nginx-demo-v4",
"Options": {},
"Scope": "local"
}
]
启动一个挂载数据卷的nginx容器webserver4:
docker run -d -p 81:80 \
--name webserver4 \
--mount source=nginx-demo-v4,target=/usr/share/nginx/html \
nginx
再启动一个挂载数据卷的nginx容器webserver5:
docker run -d -p 82:80 \
--name webserver5 \
--mount source=nginx-demo-v4,target=/usr/share/nginx/html \
nginx
修改下webserver4的默认nginx页面:
docker exec -it webserver4 bash
echo '<h1>Hello,Docker!</h1>' > index.html
从浏览器查看两个容器的页面都会被修改,在宿主机上查看文件也会被修改:
cd /var/lib/docker/volumes/nginx-demo-v4/_data
cat index.html
5.3 网络端口映射:
容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 -P
或 -p
参数来指定端口映射。
-
使用随机映射端口:
当使用
-P
标记时,Docker 会随机映射一个49000~49900
的端口到内部容器开放的网络端口。docker run -d -P --name webserver6 nginx
-
使用指定端口映射:
使用
hostPort:containerPort
格式,将本地的端口映射到容器的端口。docker run -d -p 87:80 --name webserver7 nginx
查看容器的端口映射:
docker port CONTAINER [PRIVATE_PORT[/PROTO]]
docker port webserver7
第六章 Docker仓库
默认镜像仓库是DockerHub:(https://hub.docker.com/)
公有云镜像仓库:阿里云,腾讯云等等
私有镜像仓库:registry(官方的registry),Harbor
docker image pull <repository>:<tag>
#拉取最新的ubuntu镜像
docker image pull ubuntu:14.04
#把最新的ubuntu镜像重新打标签为my-ubuntu:v1
docker tag ubuntu:latest my-ubuntu:v1
私有镜像仓库
因为 Docker 默认不允许非 HTTPS
方式推送镜像。我们可以通过 Docker 的配置选项来取消这个限制。
cat /etc/docker/daemon.json
{
"insecure-registries": [
"http://10.1.129.123:81"
]
}
网友评论