/ 服务和运维

快速上手 Docker

本文参考或引用了以下文章中的部分内容:

Docker 有什么优势? - 小狐濡尾的回答 - 知乎 https://www.zhihu.com/question/22871084/answer/88293837
【 全干货 】5 分钟带你看懂 Docker ! - 腾讯云技术社区的文章 - 知乎 https://zhuanlan.zhihu.com/p/30713987
只要一小时,零基础入门Docker - 笑虎的文章 - 知乎 https://zhuanlan.zhihu.com/p/23599229
一篇不一样的docker原理解析 - uncle creepy的文章 - 知乎 https://zhuanlan.zhihu.com/p/22382728
一篇不一样的docker原理解析 提高篇 - uncle creepy的文章 - 知乎 https://zhuanlan.zhihu.com/p/22403015
神奇的Docker到底做了什么 - 不是油条的文章 - 知乎 https://zhuanlan.zhihu.com/p/28273941

目录

  • 一、Docker简介
  • 二、如何使用 Docker
  • 三、Docker Stack
  • 四、在 CI/CD 中使用 Docker 的基本模型
  • 五、总结

一、Docker 简介

1. Docker 的优点

在说 Docker 的优点之前,我们先来说说为什么要有 Docker,先来看一个 Docker 出现之前,发生在运维身上的例子:

在docker出现之前,比如说要部署一个django(一个流行的python web服务框架)应用,要做哪些事情?

  • 首先得有个python环境,比如这个要部署的应用基于python3,而你机器上是python2,那ok,先装个python3吧,一看装起来还挺麻烦,要先装各种依赖,还要解决一些可能的冲突,没办法硬着头皮上吧。
  • 装完python之后,发现还要装mysql,还用了redis。没办法,继续下载,安装,配置。费了九牛二虎之力终于搞完了,一天就这么过去了。
  • 啥?你告诉我原来的服务器不用了,要换一台服务器?我靠,那重新来一遍吧。
  • 啥?你说咱们的基础应用做的太好,要进行推广,需要指导其他厂商部署?我选择狗带

可以看出,在有 Docker 之前,软件行业的运维存在着以下这些痛点:

  1. 软件的发布和部署低效又繁琐,而且总是需要人工介入
  2. 环境的一致性难移保证
  3. 在不同环境之间迁移的成本较高

相比较之下,Docker 具有以下优点:

  1. 软件构建容易,分发简单
  2. 应用得到隔离,依赖被解除
  3. 可以完美地用于 CI/CD
  4. 快速部署,测试完以后销毁也方便

那么,Docker 是怎么做到这些优点的呢?接下来看看 Docker 的概念和原理。

2. Docker 的基本概念和原理

在之前,为什么运维会有以上痛点,主要是因为软件的发布和部署都要依赖于外部环境,比如在 Linux 上和在 Windows Server 上,只能各自去安装软件需要的依赖,配置各自的环境,最后在一切都准备好以后,再把我们的软件部署在服务器上,而且由于开发环境和服务器上的环境还可能不一致,导致最后软件在开发的本地是工作的,但到了服务器上就崩了,可以说是非常头疼的事。

基于这种现状,Docker 给出的解决方案是,利用容器虚拟化技术,将软件运行在沙箱内,Docker 为软件提供了模拟的文件系统,进程系统还有网络IO,相当于把应用运行在了虚拟机中一样,这样就为软件提供了统一的外部环境,从而实现了一次构建,到处部署

Docker 使用过程中的一些基本概念

Docker 基本的运作机制,如下图:

Docker 运作机制

其中涉及到的一些关键概念如下:

Image 镜像

在docker中镜像是指,把应用按照docker规定的格式封装成一种具有某种标准规格的东西(就像集装箱把货物封装起来类似)。形象的说,就是把应用按照一定的格式抽象的画了个画像。类似于虚拟机中的镜像,镜像是一个包含有文件系统的面向Docker引擎的只读模板。任何应用程序运行都需要环境,而镜像就是用来提供这种运行环境的。例如一个Ubuntu镜像就是一个包含Ubuntu操作系统环境的模板,同理在该镜像上装上Apache软件,就可以称为Apache镜像。

镜像为 Docker 提供了统一规格的”原材料”,有了这些统一规格的原材料,才能实现在各种环境中都能以相同的方式使用 Docker。

Container 容器

类似于一个轻量级的沙盒,可以将其看作一个极简的Linux系统环境(包括root权限、进程空间、用户空间和网络空间等),以及运行在其中的应用程序。Docker引擎利用容器来运行、隔离各个应用。容器是镜像创建的应用实例,可以创建、启动、停止、删除容器,各个容器之间是是相互隔离的,互不影响。注意:镜像本身是只读的,容器从镜像启动时,Docker在镜像的上层创建一个可写层,镜像本身不变。

容器可以认为是一个镜像的实例,有了容器,我们可以避免直接去操作镜像,运行时的东西可以在容器中进行读取,从而避免对统一的镜像造成改变。

Docker Registry

类似于 NPM,NPM 用于管理 node.js 的包,我们需要任何包,都可以直接从 npm 上拉取。Docker Registry 就是 Docker 镜像的仓库,当我们需要任何镜像时,都可以直接从 Docker Registry 上拉取到本地。

Docker 的实现原理

关于 Docker 的实现原理,可以参考这几篇文章:

一篇不一样的docker原理解析
一篇不一样的docker原理解析 提高篇
神奇的Docker到底做了什么

二、如何使用 Docker

本文会略过 docker 的安装部分,因为这部分官方文档里已有非常好的介绍,有需要直接查看官方文档Install Docker即可。

1. Dockerfile

要使用 docker,必须要有镜像,制作一个镜像最常规的方式就是 Dockerfile,这个文件大致像下面这样:

# Use an official Python runtime as a parent image
FROM python:2.7-slim

# Set the working directory to /app
WORKDIR /app

# Copy the current directory contents into the container at /app
ADD . /app

# Install any needed packages specified in requirements.txt
RUN pip install --trusted-host pypi.python.org -r requirements.txt

# Make port 80 available to the world outside this container
EXPOSE 80

# Define environment variable
ENV NAME World

# Run app.py when the container launches
CMD ["python", "app.py"]

FROM python:2.7-slim,表明当前镜像使用了 python 的一个官方镜像: python:2.7-slim
WORKDIR /app,设置容器内的工作目录为 /app
ADD . /app,会把当前目录的内容添加到容器内的 /app 目录中
RUN pip install --trusted-host pypi.python.org -r requirements.txt,会在镜像运行前,提前运行这个命令,把一些应用启动需要的依赖安装好
EXPOSE 80,把容器的 80 端口暴露给宿主机
ENV NAME World,设置容器内的环境变量
CMD ["python", "app.py”],容器启动时执行的命令

通过这个文件,我们运行 docker build 命令,就可以得到一个自己制作的 Docker 镜像,并把它发布到 Docker 仓库上,这里是发布相关的操作:share your image

2. docker pull image-name:tag

docker pull 命令会从 Docker Registry 上拉取一个特定版本的镜像,例如 docker pull centos,会默认从 Docker Hub 上拉取 centos 这个镜像的最新版,当需要拉取特定版本的镜像时,在镜像名后面加上 tag 即可,例如 docker pull centos:7。更多关于镜像的操作,直接运行 docker image 即可看到。

3. docker run iamge-name:tag

docker run 命令可以通过一个本地的镜像启动一个容器,也就是一个应用。还可以在运行时加上一些附加参数。例如 docker run -it centos:latest /bin/bash 将会立即启动一个 centos 容器。参数 i 表示容器的输入输出会直接在当前终端上显示,参数 t 表示当前终端会切换到容器内的终端。更多关于容器的操作,直接运行 docker container 即可看到。

另外其实我们可以直接运行 docker run <image-name:tag>,当本地没有对应的镜像时,Docker 实际上会自动去拉取的。

对于镜像的”消费者”来说,以上两个命令就可以运行起我们需要的一个应用了。

如果有对 Docker 命令更深入了解的需求,查看 Docker command line 即可

4. docker-compose

docker-compose 是一个辅助工具,通过它,可以组合多个容器为一个应用,其使用方法为:先新建一个 docker-compose.yml 文件,定义好应用需要启用哪些服务,用哪些镜像启动容器,以及相关的网络设置等。之后通过docker-compose run <service-name> 即可组合运行期一个应用。以下为一个 docker-compose.yml 示例文件:

version: "3"
services:
  web:
    # replace username/repo:tag with your name and image details
    image: username/repo:tag
    deploy:
      replicas: 5
      resources:
        limits:
          cpus: "0.1"
          memory: 50M
      restart_policy:
        condition: on-failure
    ports:
      - "8080:80"
    networks:
      - webnet
networks:
  webnet:

通过这个配置文件,我们可以得到以下信息:

  • 这是这个应用的第三个配置版本
  • 这个应用内只有一个服务 web,并且使用了 webnet 这个网络
  • web 服务使用了 username/repo:tag 这个镜像;其在部署时共有5个副本,以实现负载均衡;它的资源占用被限定在了 10% 的 CPU 占用率, 50M 内存以下;web 服务在运行失败的时候,会自动重启;web 服务会将容器内的80端口映射到宿主机的8080上,因此可以在宿主机的8080端口上访问到这个应用;web 服务使用了 webnet 这个 Docker 网络。

一般一个真正的应用都不可能只用到一个镜像,通过 docker-compose 这种方式,可以让我们在部署应用的时候更加方便,让部署和更改配置直接在”应用”层级上进行操作,而不用一个个地去操作容器。

三、docker-stack

这一块涉及到在分布式集群中,如何部署我们的运用。Docker 在这方面的”设计哲学”是,对于一个分布式的应用,分为以下三个层级: Containers, Services, Stack。这一部分,在Docker 文档中有清晰且完整的叙述Services,接下来我们从基本流程上来阐述一下如何搭建一个分布式的应用:

要实现一个分布式的运行,首先要组成 swarm,将当前的宿主机设置成一个 swarm 的节点:

docker swarm init

之后利用 docker-compose.yml 文件,在一个节点上运行起我们的服务

docker stack deploy -c docker-compose.yml webservice

现在,我们的 swarm 里面只有一个节点,现在在我们的分布式节点上,将其它 swarm node 加入到这个 swarm 中

docker swarm join --token :

这样我们就将一个分布式的集群联结起来了,并在这个集群中运行了我们的应用。这一块我也没有在日常中真正使用过,所以如果有需要,还请到官方文档中去做更深入的了解。

四、在CI/CD中使用 Docker 的基本模型

CI/CD 可以帮助我们更好地实现集成和部署,开发人员利用 Git push 完代码后,剩下的事情就不用关心了, CI/CD 可以自动地把新版本的应用部署到服务器上。以下为实现 CI/CD 的基本模型:

CI/CD

  1. RD推送代码到 git 仓库或者 SVN 等代码服务器上面,Git 服务器就会通过 hook 通知 jenkins。
  2. jenkine 克隆 Git 代码到本地,并通过 Dockerfile 文件进行编译 。
  3. 打包生成一个新版本的镜像并推送到仓库 ,删除当前容器 ,通过新版本镜像重新运行。

在整个过程中 RD只需要敲入三个命令 git add *, git commit –m “”, git push 即可完成持续集成、自动交付、自动部署。

总结

本想尽量把这 Docker 的东西说得完善的,后来写文章的过程中发现这一块的东西的确很多很大,因此就利用了 MVP(minimum viable product) 的原则,将我认为最常用和最重要的部分挑出来说了一下。希望能对看到这篇文章的人有所帮助。DevOps 是一块有趣又博大精深的内容,基于 Docker 能做的好玩的事情很多,还可以为我们节约很多的精力,值得去做更多的探索。