计算机系统应用教程网站

网站首页 > 技术文章 正文

一文掌握Docker及其实战场景 docker通俗易懂

btikc 2024-10-23 09:12:55 技术文章 6 ℃ 0 评论

我们先看看谷歌热度上Docker关键字的趋势,从2014年开始,Docker 热度持续不减。

https://trends.google.com/trends/explore?date=all&geo=CN&q=Docker

1. Docker的场景

1.1 模板配置

Docker 提供了一个通用配置文件dockerfile。在初次配置成功后,它可以作为一个模板文件增加不同应用的相关文件。

随着应用逐渐增多,研发人员只需维护好与之对应的 Docker 配置文件即可,而这个配置文件则固定的分为几个标签,每个标签标识docker的一些属性,同时存储了Docker 运行、启动的命令。

1.2 CI/CD

Docker 提供了一组应用打包构建、传输及部署的方法和框架,用户只需要关注自己的逻辑功能,框架会自动被触发构建和运行。Docker 还提供了跨越这些异构环境以满足一致性的微环境——从开发到部署、再到流畅发布,同时提高资源的配置和隔离方案。

目前通用的实践就是和Jenkins、GitLab 等相关工作流平台串联起来,融入项目开发的CI/CD(持续集成与持续发布)流程中,让一键部署成为可能。

1.3 DevOps节点运行能力

在传统软件开发过程中,开发、测试和运维是不同的软件开发的流程,甚至不是一个团队成员。对于互联网公司而言,由于业务迭代非常的快,需要通过“小步快跑”的方式进行敏捷开发,以此来满足用户差异化的需求、应对竞争对手的产品策略。如果在周级别的迭代过程中需要管理环境、人员调配,资源评估,那将是非常糟糕的。因此,在极端情况下,如:每周发布多次甚至每天发布多次的场景,高效的团队协作就显得尤为重要。

DevOps 正式在这种场景下应运而生,它打破了开发人员和运维人员之间的壁垒,通过“节点服务”组成工作流,串联项目完整生命周期,涵盖了研发、构建、测试、发布、监控及反馈等流程,从而促进了软件的一致性和标准化,支持节点可重入,可回滚,可灰度发布的能力,严格管控传统低效的开发流程,让这一切变得更智能化。

标准的“节点服务”依赖一些隔离的执行环境:既要快速启停、又要服务稳定执行、还要支持高并发调度,这一切都可以通过 Docker 来轻松实现。

1.4 自动化测试

测试是软件开发过程中非常关键的一环,直接影响产品的质量。测试工程师每天都需要完成大量的测试任务,手动执行测试会耗费大量的时间,这时考虑使用 Docker 进行自动化改造。自动化的成本是首次自动化程序的编写和维护,而收益则是解放人力、提高生产力。

测试人员在进行一些功能测试、性能测试以及UI测试时,需要快速搭建不同的运行环境、掌握Docker技术,可以让测试人员如虎添翼。

1.5 应用服务隔离

隔离是当今微服务发展与部署的核心考核点,服务之间的资源刚性交付和保证是服务上线后稳定运行的基本。例如,服务器上混部了两个服务:

  • Node服务,用来启动Web应用服务;
  • Java服务,用来提供前后端分离的API接口和业务逻辑。

如果服务混部就可能出现这种情况——两个服务争夺服务器的CPU资源,无论哪一方失败都将造成灾难。如下图所示,服务器的CPU资源已经被Java服务占满,此时node服务就会饥饿等待。

在资源有限的前提下,操作系统没法同一时间满足多个应用进程的突发流量使用。当然,在这种场景下可以通过独立部署、为虚拟机设定资源优先级等方案解决,但是这个扩容能力和效率会比较低,同时资源也不好准确评估。

但在 Docker中,这些完全没有必要担心,因为Docker提供了进程级的隔离,可以更加精细地设置CPU和内存的使用率,进而更好地利用服务器的资源。

1.6 弹性扩缩容

在生产实践中,业务不可避免的产生突发流量,比如双11的整点抢购、游戏服务的活动大礼包开放、节假日的各种优惠活动等都会带来流量的波动。在大促或流量不均的场景,服务器的自动扩容/缩容就会很关键。

在流量低谷时进行自动缩容,可以大幅度减少服务器成本。在峰值来临时,通过可观测性预测自动触发服务器扩容操作,从而保证服务器稳定运行。

在传统的虚拟机或物理机的实战中,这些操作显得非常的繁琐和低效。而在Docker中却非常灵活并且高效,因为,每个容器都可作为单独的进程运行,并且可以共享底层操作系统的系统资源。这样可以提高容器的启动和停止效率,扩容也就毫不费力了。

1.7 节省成本

成本优化也是很多企业使用Docker的原因之一。传统企业一般会使用虚拟机,虚拟机虽然可以隔离出很多“子系统”,但占用的空间更大,启动更慢。在线和离线服务没有混部充分利用服务器资源。

Docker技术不需要虚拟出整个操作系统,只需要虚拟出一个小规模的环境,与“沙箱”类似,达到开箱即用的效果。

此外,虚拟机一般要占用很大的存储空间(可以达到数十GB);而容器只需要占用很小的存储空间(最小的仅为几KB),这样就能节省出更多的服务器资源,从根本上节省成本。

可以看出,Docker已经渗透到了日常开发的方方面面。

2. Docker技术体系

2.1 Docker架构

我们看如下图:


docker架构主要包含:

Docker Client:docker client 是docker架构中用户用来和docker daemon建立通信的客户端,用户使用的可执行文件为docker,通过docker命令行工具可以发起众多管理container的请求。docker client发送容器管理请求后,由docker daemon接受并处理请求,当docker client 接收到返回的请求相应并简单处理后,docker client 一次完整的生命周期就结束了,当需要继续发送容器管理请求时,用户必须再次通过docker可以执行文件创建docker client。

Docker Server:在Docker的启动过程中,通过包gorilla/mux(golang的类库解析),创建了一个mux.Router,提供请求的路由功能。在Golang中,gorilla/mux是一个强大的URL路由器以及调度分发器。该mux.Router中添加了众多的路由项,每一个路由项由HTTP请求方法(PUT、POST、GET或DELETE)、URL、Handler三部分组成。

  • Daemon:docker daemon 是docker架构中一个常驻在后台的系统进程,功能是:接收处理docker client发送的请求。该守护进程在后台启动一个server,server负载接受docker client发送的请求;接受请求后,server通过路由与分发调度,找到相应的handler来执行请求。docker daemon启动所使用的可执行文件也为docker,与docker client启动所使用的可执行文件docker相同,在docker命令执行时,通过传入的参数来判别docker daemon与docker client。
  • Containerd:Docker 引擎中的 Containerd 组件确保了 Docker 镜像能够以正确的 OCI Bundle 的格式传递给 Runc;
  • Runc:实质上是一个轻量级的、针对 Libcontainer 进行了包装的命令行交互工具,可以理解为一个独立的容器运行时工具。作用只有一个——创建容器。

Docker Driver:

  • Execdrive:存储了容器定义的配置信息了,Libcontainer 拿到这些配置信息后,将会调用底层的 Namespace 和 Cgroup 等技术来完成容器的创建和管理;
  • Networkdirver:主要作用是完成 Docker 容器的网络环境配置,包括容器的 IP 地址、端口、防火墙策略,以及与主机的端口映射等;
  • Graphdriver:主要负责对容器镜像的管理。

Linux Kernel:

  • Chroot:即 change root directory (主要用来更改 root 目录)。在 Linux 系统中,系统默认的目录结构都是以 /,即以根 (root) 开始的。而在使用 Chroot 之后,系统的目录结构将以指定的位置作为 / 位置;
  • Namespace:是 Linux 内核用来隔离内核资源的方式,目的就是实现轻量级虚拟化(容器)服务,为 Docker 等容器技术提供了基础条件;
  • Cgroup:是 Linux 内核提供的一种可以限制单个进程或者多个进程所使用资源的机制,可以对 CPU、内存等资源实现精细化的控制,Docker 就使用了 Cgroup提供的资源限制能力来完成 CPU,内存等部分的资源控制;
  • Network:为 Docker 容器提供多种网络解决方案;
  • Capability:Linux 引入了 Capabilities 机制对 root 权限进行细粒度的控制,实现按需授权,从而减小系统的安全攻击面;
  • Seccomp:即安全计算模式,可以使用它来限制容器内可用的操作。seccomp()系统调用在调用进程的seccomp状态下运行。Docker 中使用此功能来限制应用程序的访问;
  • Filesystem:UnionFS 通过 Linux Filesystem 为容器提供高效的管理能力。Docker 的镜像就采用了 UnionFS 技术,从而实现了分层的镜像。

Docker的生命周期:

2.2 Docker 周边生态

如果需要搭建“企业级容器化标准”,那么一定要对 Docker 周边生态有足够的了解,不妨一起从下图中感受整个技术体系。

从生态图中我们看到,Docker涉及到很多工具或平台。但万变不离其宗,“企业容器化标准”可以归纳以下几方面:

  • 服务发现:Etcd、ZooKeeper、Consul、Eureka、istio
  • 负载均衡:Nginx、F5、LVS、DNS
  • 日志管理:两种模式Daemonset集中式和Sidecar自定义,ELK
  • 链路追踪:Pinpoint、Jaeger 、SkyWalking、Zipkin、SkyWalking
  • 容器编排:Swarm、Kubernetes、Mesos、consul
  • 数据存储:Redis、MySQL、MongoDB、Nebula
  • 弹性部署:定时扩容、手动扩容、自动扩容
  • 网络选型:Flannel、Calico、Weave、自研
  • 存储系统:PV/PVC声明文件、StorageClass动态供给
  • 部署发布:Jenkins、GitLab、Registry
  • 服务监控:Zabbix、Nagios、cAdvisor、Prometheus
  • 集群可靠性:资源预留、集群预留、集群组件(API Server、Etcd集群方案、kube-scheduler与controller-manager)

3. Dockerfile

我们可以使用Dockfile构建一个镜像,然后直接在docker中运行。Dockerfile文件为一个文本文件,里面包含构建镜像所需的所有的命令,首先我们来认识一下Dockerfile文件中几个重要的指令。

3.1 指令详解

FROM

基础镜像,然后在基础镜像上进行修改

RUN

RUN指令用来执行命令行命令的。它有以下两种格式:

  • shell 格式:RUN <命令>,就像直接在命令行中输入的命令一样。RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
  • exec 格式:RUN ["可执行文件", "参数1", "参数2"],这更像是函数调用中的格式。

CMD

此指令就是用于指定默认的容器主进程的启动命令的。CMD指令格式和RUN相似,也是两种格式

  • shell 格式:CMD <命令>
  • exec 格式:CMD ["可执行文件", "参数1", "参数2"...]
  • 参数列表格式:CMD ["参数1", "参数2"...]。在指定了 ENTRYPOINT 指令后,用 CMD 指定具体的参数。

ENTRYPOINT

ENTRYPOINT 的格式和RUN指令格式一样,分为 exec 格式和 shell 格式。 ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数。ENTRYPOINT 在运行时也可以替代,不过比 CMD 要略显繁琐,需要通过 docker run 的参数 --entrypoint 来指定。当指定了 ENTRYPOINT 后,CMD 的含义就发生了改变,不再是直接的运行其命令,而是将 CMD 的内容作为参数传给 ENTRYPOINT指令,换句话说实际执行时,将变为:

<ENTRYPOINT> "<CMD>"

COPY & ADD

这2个指令都是复制文件,它将从构建上下文目录中 <源路径> 的文件/目录 复制到新的一层的镜像内的 <目标路径> 位置。ADD指令比COPY高级点,可以指定一个URL地址,这样Docker引擎会去下载这个URL的文件,如果ADD后面是一个tar文件的话,Dokcer引擎还会去解压缩。

EXPOSE

声明容器运行时的端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。在 Dockerfile 中写入这样的声明有两个好处,一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;另一个用处则是在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。要将 EXPOSE 和在运行时使用-p <宿主端口>:<容器端口> 区分开来。-p是映射宿主端口和容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,而 EXPOSE 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射。

ENV

这个指令很简单,就是设置环境变量,无论是后面的其它指令,如 RUN,还是运行时的应用,都可以直接使用这里定义的环境变量。它有如下两种格式:

  • ENV <key> <value>
  • ENV <key1>=<value1> <key2>=<value2>...

VOLUME

该指令使容器中的一个目录具有持久化存储的功能,该目录可被容器本身使用,也可共享给其他容器。当容器中的应用有持久化数据的需求时可以在Dockerfile中使用该指令。如VOLUME /tmp这里的 /tmp 目录就会在运行时自动挂载为匿名卷,任何向 /tmp 中写入的信息都不会记录进容器存储层,从而保证了容器存储层的无状态化。当然,运行时可以覆盖这个挂载设置。比如:docker run -d -v mydata:/tmp xxxx

LABEL

镜像添加labels,用来组织镜像,记录版本描述,或者其他原因,对应每个label,增加以LABEL开头的行,和一个或者多个键值对。如下所示:

LABEL version="1.0"
LABEL description="test"

4. Docker的常见操作

启动、重启和开机docker自启动systemctl enable docker

# Docker的启动
systemctl start docker
# Docker的重启
systemctl restart docker
# Docker的开机自启动
systemctl enable docker     # 一般我们使用开机自启动的形式

4.1 镜像的基本操作

  • 使用search命令来检索中央仓库中收录的镜像,这里以nginx为例
# 检索镜像:docker search [镜像名称]
docker search nginx
  • 拉取(下载)镜像:docker pull nginx(默认最新版本),如果需要其他版本可在中央仓库中查阅
# 拉取镜像:docker pull [镜像名称]
docker pull nginx
# 默认拉取的是最新版本,如果需要特定版本,在后面指定即可,nginx7.0.1为例
docker pull nginx:7.0.1
  • 查看已经下载的本地镜像:
# 查看已经下载的本地镜像
docker images


删除本地镜像

# 删除本地镜像: docker rmi 镜像名称/IMAGE ID
docker rmi nginx

4.2 容器的基本操作

  • 根据镜像启动对应的容器
# 根据镜像启动对应的容器
docker run -d --name mynginx nginx
# --name 对容器起一个别名
# -d 对指定的容器进行后台运行
  • 停止运行的容器
# 停止运行的容器:docker stop 容器名称/CONTAINER ID
docker stop mynginx
  • 查看正在运行的容器
docker ps       # 查看正在运行的容器
docker ps -a    # 查看本地所有的容器
  • 删除容器
# 注:删除容器是使用rm,删除镜像是rmi,且删除镜像之前需要停止运行容器并删除
docker rm mynginx
  • 启动一个做了端口映射的容器,在之前创建容器之后,我们无法通过ip:端口的形式来访问Docker中所开启的服务,因为每一个容器他都是独立,所以要想访问,我们则需要通过端口的映射来访问容器。
docker run -d --name mynginx -p 8888:8080 nginx
# --name:对容器起一个别名
# -p:将主机的端口映射到容器的一个端口  主机端口:容器内部的端口 
# -d:后台运行
  • 查看容器的日志docker logs mytomcat
  • 容器开机自起动:
docker update mynginx --restart=always
  • 进入对应的容器
docker exec -it mynginx /bin/bash
  • 本地文件(是centos不是windows)与docker容器中文件之间的互传,以将ik分词器插件上传至elasticsearch容器为例:
# 先将windows上的文件使用xftp上传到vmware linux中,然后将文件使用docker命令上传到docker容器中
# docker cp 本地路径 容器名:容器路径
docker cp ./elasticsearch-analysis-ik-6.5.4.zip elasticsearch:/usr/share/elasticsearch/plugins
  • 文件的挂载

Docker容器是独立,且其相当于是一个及其精简版的Linux,在我们通过exec命令之后,我们是无法使用vim、vi等命令来对其内部文件进行编辑,在一般情况下我们在创建好容器之后一般会对其配置文件进行编辑,此时我们可以使用Docker中的挂载来将容器内文件挂载到宿主机中。当我们在宿主机中对挂载的文件进行编辑的时候,容器中所被挂载的文件也会做出相应的修改,下面就是docker挂载文件的-v操作(以挂载Es的配置文件和数据文件为例):

mkdir -p ./resources/elasticsearch/config
mkdir -p ./resources/elasticsearch/data

docker run --name elasticsearch -p 9200:9200 \
-e "discovery.type=single-node" \
-e ES_JAVA_OPTS="-Xms256m -Xmx256m" \
-v /resources/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /resources/elasticsearch/data:/usr/share/elasticsearch/data -d elasticsearch:5.6.8

4.3 镜像、容器的导入和导出

export:可将docker容器通过export导出为tar文件

docker export mynginx > mynginx.tar

import:基于tar文件来创建一个新的镜像

docker import - mynginx < mynginx.tar

注:以下表格总结了Docker容器中常用的一些命令。

api

描述

docker logon

登录到docker registry

docker logout

从docker registry退出登录

docker pull

从docker registry中拉取docker镜像

docker image ls

列出本地已经下载的镜像列表

docker image rm

删除本地镜像

docker push

将本地镜像推送的docker registry

docker attach

将本地标准的输入,输出和错误流关联到一个正在运行的容器

docker build

使用dockerfile构建一个docker镜像(image)

docker cp

实现容器与本地文件系统之间文件跟目录的拷贝

docker commit

将对容器修改部分添加到docker镜像中并创建新的docker镜像

docker config

管理docker配置文件

docker create

创建一个新的容器

docker start

启动某个已经stopped的容器

docker run

启动一个新的容器并执行某个command

docker exec

在某一个正在运行的docker容器中执行某个command

docker rm

移除某容器

docker restart

重启某个docker容器

docker pause

暂停某个容器中的所有进程

docker unpause

将容器中已暂停的所有进程恢复执行状态

docker stop

停止某个docker容器

docker kill

杀掉某个正在运行的容器

docker info

显示系统层面的信息

docker logs

抓取docker容器中的所有日志

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表