Docker 作为近几年非常热门的技术,来看看到底有什么优势值得我们去尝试。

前言

Docker 是近几年非常热门的技术之一,相信你在工作或者学习中总能听到这项技术,现如今 Docker 容器化技术的使用已经在各大厂商已经非常普遍,作为前端,或许你编写的应用是跑到服务器的 Docker 容器当中,然而你并不知道,因为许多公司已经将其“封装”为一个黑盒,完善的 DevOps 工具让你只专注与自己领域的开发,你并不需要知道项目是在哪里构建、在哪里运行,作为一个自我驱动型的工程师,拓展自己的技术广度还是很有必要的,本篇文章将会介绍 Docker 的基本使用方式以及如何创建一个持续发布流程。

Docker 入门

什么是 Docker

Docker 是 Linux 容器的一种封装,提供简单易用的容器使用接口,Docker 将应用程序打包在一个文件(镜像)中,运行这个文件,就会生产一个虚拟的操作系统(容器),程序运行在容器中,就像运行在真实的物理机中,使用 Docker 相比传统的虚拟机有很多优势:

  • 启动快: 运行一个容器就相当于运行宿主机底层系统中的一个进程,也就相当于启动宿主机中的进程,而不是要启动一个完整的操作系统,因此速度会非常快。
  • 占用资源少:虚拟机由于是完整的操作系统,需要占用大量资源,容器只需要占用“需要”的资源,不占用没有使用到的资源,并且多个容器可以共享宿主机中的资源,因此其占用的资源相比于虚拟机要少很多。
  • 体积小:容器只需要打包“用到”的组件,而虚拟机是整个操作系统的打包,所以体积上容器要小很多。

几个关键的部分

作为入门实践,我们只需要关心几个关键的部分便能上手实现我们想要的功能:

镜像(Image)

镜像是一个文件,如果你重装过系统,我们需要下载该系统的镜像,那么 Docker 中的镜像就是用来装“系统”(Container)的文件包,其中包含了虚拟环境运行最原始文件系统的内容。

Dockerfile

上面我们说的镜像是一个文件包,不同的需求我们需要定制不同的镜像,通常我们使用 Dockerfile 来构建镜像,Dockerfile 中包含一些构建镜像的命令,比如有下载某个软件包、复制某些文件、对项目进行打包、更改 nginx 的配置等等,总之我们的目的是构建一份“拿来即用”的“装机”文件包。

容器(Container)

容器可视为一个完整的操作系统,容器由镜像创建而成,可以在容器当中做一切当前操作系统能做的事情,比如运行一个 Node.js 脚本、运行一个 nginx 服务器为客户端提供服务。

宿主机(Host)

宿主机是你购买的云服务器或者你本地 pc,这是 Docker 运行的宿主,宿主机中包含许多镜像与容器,容器之间是完全隔离开来的。

用一张图来表示其几个关键部分的关系:

image

简单实战

这个章节讲解一个最简单的 Docker 实践,我们将构建一个 Nginx 服务器,并且用来处理一个 index.html 静态 html 文件,访问对应的 ip 与 端口,便能访问到这个静态 html 页面。

安装 Docker

假如在本地 PC 端安装,直接点下面链接,便能下载最新稳定版本的安装包:

MacOS : https://download.docker.com/mac/stable/Docker.dmg

Windows: https://download.docker.com/win/stable/Dock…

如果是在 Linux 系列系统上安装,这篇教程中提供了详细的说明:史上最全(全平台)docker安装方法!

创建 Dockerfile 及 其他文件

  1. 首先我们创建一个文件夹: docker-test
1
mkdir docker-test
  1. 然后其目录下创建两个文件:Dockerfileindex.html
1
touch Dockerfile index.html
  1. 编写 index.html
1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
this is docker test
</body>
</html>

这是作为访问静态页面的 html 文件。

  1. 编写 Dockerfile
1
2
3
4
5
FROM nginx

COPY ./index.html /usr/share/nginx/html/index.html

EXPOSE 80

第一步: FROM nginx 表示该镜像是基于官方的 nginx 来构建的,这里就相当于下载了一个包含 nginx 服务且“拿来即用”的镜像。

第二步: COPY xxx xxx 表示将当前项目中的 index.html 复制到 nginx 默认的初始页位置。

第三步:EXPOSE 80 表示将容器 80 端口暴露出来, 允许外部连接这个端口。

这里我们完成了一个镜像需要的文件包,下一步,我们将基于该文件包,构建一个可以真正运行的镜像。

构建镜像

有了 Dockerfile 文件以后,我们就能使用 Docker 的命令: docker image build 来构建镜像了。

1
docker image build -t docker-test:v1 .

上面命令中,-t 参数用来制定镜像的名称,冒号后面是镜像的标签,如果不指定,默认的标签就是 latest,最后我们一定要注意,这句命令中,最后还有一个.,这里表示的是当前路径,也就是 Dockerfile 所在的路径。

运行该命令后,我们将会得到一下输出:

1
2
3
4
5
6
7
8
9
Step 1/3 : FROM nginx
latest: Pulling from library/nginx
Status: Downloaded newer image for nginx:latest
---> 231d40e811cd
Step 2/3 : COPY ./index.html /usr/share/nginx/html/index.html
---> 68aa4c9ded77
Step 3/3 : EXPOSE 80
---> Running in 9e2db6a09b00
Successfully tagged docker-test:v1

我们可以看到,输出信息的每个 Step 都对应着 Dockerfile 中的每个指令,这也方便我们查看构建信息与 debug,构建完成后,我们在命令航中输入:

1
docker image ls

我们会看到刚刚构建的镜像已经在列表当中:

1
2
REPOSITORY                              TAG                 IMAGE ID            CREATED             SIZE
docker-test v1 567da52d5085 15 minutes ago 126MB

到这里已经表示我们完成了整个镜像的构建,下一步我们将会运行该镜像,启动一个容器。

运行容器

现在到了整个链路中最后一步, 创建并运行容器。

在命令行中输入 docker container create 命令来创建一个容器:

1
docker container create -p 3303:80 docker-test:v1

命令中 -p 表示 port ,还记得我们 Dockerfile 中的 EXPOSE 80 指令吗,上面的 80 端口,指的是容器中的 80 端口,而不是宿主机的端口,假设想要访问到容器中的 80 端口,我们需要做一个 宿主机—> 容器 的端口映射,-p 3303:80 表示的是将宿主机的 3303 端口映射到容器的 80端口,这时候我们便能通过宿主机的 3303 端口访问到容器的 80 端口。命令中的 docker-test:v1 指的是用哪个镜像来创建容器,命令执行完毕后,会输出一条容器ID:

接着我们运行 docker container ls -a 来查看所有(-a)的容器:

1
2
CONTAINER ID        IMAGE                           COMMAND                  CREATED             STATUS              PORTS               NAMES
95696808d7e4 docker-test:v1 "nginx -g 'daemon of…" 21 seconds ago Created condescending_shirley

我们看到,该容器的 STATUSCreated 状态,还未处于运行状态,我们输入 docker container start CONTAINER ID 来运行容器:

1
docker container start 95696808d7e4

这个时候,访问:http://localhost:3303/ ,便能访问到 index.html 静态文件了,这个时候我们再运行 docker container ls -a

1
2
CONTAINER ID        IMAGE                           COMMAND                  CREATED             STATUS              PORTS                  NAMES
95696808d7e4 docker-test:v1 "nginx -g 'daemon of…" 11 minutes ago Up About a minute 0.0.0.0:3303->80/tcp condescending_shirley

可以看到,STATUS 已经转变为 Up,我们设置的端口映射 PORTS 也转变为 0.0.0.0:3303->80/tcp

到这里,我们已经完成了 Docker 的基本实践,下面,我们将会进阶地实践基于 Docker 的自动发布流程。

持续发布

上面我们已经完成了 Docker 的基本实践,这一章中我会带着读者利用第三方平台 DaoCloud 创建一个持续发布流程。

场景分析

假设我们需要将一个前端项目部署在云服务器中,并且使用了 Docker 容器化技术,当应用需要更新时,我们需要进行以下步骤:

  1. 将代码 push 到 Github / Gitlab 中。
  2. 登录云服务器
  3. git clone 最新的代码
  4. 执行打包(这一步也能在本地开发环境完成)
  5. 构建 Docker 镜像
  6. 创建并运行容器

频繁发布项目的话,这些操作复杂且耗时不说,而且容易误操作,这个时候我们就需要一个自动化的发布流程,当我们只需要将测试无误后的代码,push 到特定的分支,服务器变能自动地运行上述的 2.3.4.5.6 步骤,我们称之为 持续发布 流程(workflow)。

DaoCloud

作为简单的个人应用,我们不必自己的研发一套这样的持续发布系统,目前已经有比较成熟且操作简单的免费第三方 DevOps 工具供我们个人项目使用(公司一般不会轻易使用第三方的 Devops 工具,主要原因还是担忧代码泄露),作为个人项目,我们使用 DaoCloud 作为个人 DevOps 平台。

创建新的项目

首先我们在 Github 创建一个仓库 docker-publish-demogit clone 到本地后,使用 vue 或者 react CLI 工具创建一个新的项目:

1
create-react-app docker-publish-demo

并且在项目中,创建一个 Dockerfile 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
FROM node:8.16-slim

RUN apt-get update \
&& apt-get install -y nginx

WORKDIR /app

COPY package.json /app/package.json

RUN npm i --registry=https://registry.npm.taobao.org

COPY . /app


RUN npm run build \
&& cp -r build/* /var/www/html \
&& rm -rf /app

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

第一步:基于 node 镜像来进行后续的构建步骤,因为 React 项目需要 node 环境来进行打包

第二步:我们下载了 nginx 以便我们创建静态文件服务

第三步:WORKDIR /app 中,我们创建了一个工作目录

第四步: COPY package.json /app/package.json 将项目中的 package.json 拷贝到 /app

第五步:RUN npm i 安装依赖

第六步:COPY . /app 将其所有文件(包含node_modules)拷贝到 /app

第七步:进行打包,并且将打包好的静态文件移到 nginx 配置文件中

第八步:暴露 80 端口

第九步:将 nginx 在前台运行,避免容器启动后就退出

最后,我们根据上面章节的步骤在本地试一试 Dockerfile 是否能成功构建镜像且能运行容器。

1
2
3
4
5
docker image build -t docker-publish:v1 .

docker container create -p 3304:80 docker-publish:v1

docker container start ContainerId

假设一切都没问题后,我们将代码 push 到远程仓库中,接着就开始创建我们的自动化持续发布流程。

1
2
3
git add .
git commit -m 'init project'
git push

在 DaoCloud 上创建自动构建发布流程

创建 DaoCloud 账号后,我们进入 DaoCloud 控制台

  1. 进入控制台,点击创建项目

image

  1. 新用户需要绑定 Github 的账号,获取到需要绑定的 repo,绑定 Github 后,选择需要构建的 repo

image

  1. 进入项目,点击流程定义

image

  1. 删除测试阶段以及发布阶段

image

  1. 编辑任务

image

image

这里我们设置当代码 push 到 master 分支后,开始执行构建,这一步将会在远程仓库中设置一个 webhooks,当 repo 满足上述条件后,将会触发该 webhooks:

image

由于是第一次构建,我们点击手动触发,这时候 DaoCloud 会拉取 Github 中的源码,在 DaoCould 的 runner (执行环境)中构建镜像。

  1. 创建应用

image

选择左边应用 Tab 栏,点击创建应用,选择之前构建的镜像。

image

填写应用信息,选择运行环境,这里我选择自己的云服务器(因为要对外服务)。

  1. 设置容器信息后,点击立即部署。

image

  1. 设置自动发布

image

  1. 更改项目源码,push 到远程仓库,触发 DaoCloud 进行构建镜像。

这里我们勾选自动发布,当有新的镜像构建完成后,创建新的容器并且替换上一版容器,这样便能完成自动构建及发布流程,最后,我们用一张图来总结上述整个流程:

image

总结

本篇博客,我们学习了 Docker 的基本使用方法,实践了如何构建镜像、创建及运行容器,基于这些知识,我们利用第三方 Devops 工具 DaoCloud 创建了个人项目的自动构建发布流程,使得我们只需要专注功能的实现,将这些粗活杂活交给自动化流程,节省了我们大量的时间,整个开发流程也更为现代化。

refs:

DaoCloud DevOps 文档

Docker 入门教程