译 - 面向前端开发人员的 Docker 入门指南

用户头像
费马
关注
发布于: 2020 年 06 月 08 日
译-面向前端开发人员的Docker入门指南



原文链接-Docker-for-Front-End-Developers,本文在翻译的基础上结合自己实践过程,补充了部分自己的理解。



Docker 在2013年发布以来,容器的使用量一直在上升,现在它已成为大多数技术公司的一部分。遗憾的是,在涉及前端开发时,很少有人会触及这个概念。



因此,当我们前端开发人员必须与容器化打交道时,经常会觉得费劲。这正是几周前发生在我身上的事情,那时我不得不接触公司中通常不涉及的某些服务。



其实工作任务本身很容易,但是由于缺乏关于容器化工作原理的知识,因此几乎花了我整整两天的时间来完成它。有了这些经验之后,我现在在处理容器和CI管道化时会更加稳,但是整个学习过程非常痛苦且漫长。



这篇文章的目的是教您Docker的核心概念以及如何操作容器,以便您可以专注于自己喜欢的任务!

Docker及其原因

让我们首先以简单易懂的语言定义Docker(在 Docker Curriculum的 帮助下):

Docker是允许开发人员,系统管理员等轻松地在沙盒(又称容器)中部署其应用程序以在主机操作系统上运行的工具。



使用容器的主要好处是它们可以打包代码及其所有依赖项,因此无论计算环境如何,应用程序都可以快速可靠地运行。

通过这种解耦,可以轻松且一致地部署基于容器的应用程序,而不管应用程序将部署在何处:云服务器,内部公司服务器或个人电脑。



image.png



Docker基本概念理解

三个基本概念:

  • 镜像(Image)

  • 容器(Container)

  • 仓库(Repository)

镜像

操作系统分为内核用户空间,内核启动后,会挂载root文件系统为其提供用户空间支持,而Docker镜像就相当于一个root文件系统

Docker镜像是一个特殊的文件系统,除了提供容器运行时所需的程序,库,资源,配置等文件外,还包括为运行时准备的配置参数。镜像不包含任何动态数据,其内容在构建后也不会被改变。

容器

镜像与容器的关系,就像面向对象中的类和实例,镜像是静态的定义,容器是镜像运行时的实体,容器可以被创建,启动,停止,暂停,删除等。

每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为容器存储层

容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。

按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用 数据卷(Volume) 、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。

数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器可以随意删除、重新 run,数据却不会丢失。

仓库

镜像构建完成后,可以很容易的在当前宿主上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务, Docker Registry 就是这样的服务。



前置知识

在Docker生态系统中,需要了解一些关键定义才能了解他们在说什么:



  • Image:镜像,应用程序的蓝图,构成容器的基础。它是一个轻量级的,独立的,可执行的软件包,其中包括运行应用程序所需的一切,例如代码,运行时,系统工具,系统库和设置。

  • Containers:容器由镜像像以及启动容器时提供的任何其他配置选项(包括但不限于网络连接和存储选项)定义。

  • Docker daemon:Docker守护程序,在主机上运行的后台服务,用于管理Docker容器的构建,运行和分发。守护程序是在客户端与之交谈的OS中运行的进程。

  • Docker client:允许用户与Docker守护程序进行交互的CLI。它也可以采用其他形式的客户端,例如提供UI界面的客户端。

  • Docker Hub:镜像注册表。您可以将注册表视为所有可用Docker镜像的目录。如果需要,您可以托管自己的Docker注册表并从那里拉镜像。



从’Hello World’开始



为了完全理解上述术语,让我们设置Docker并运行一个示例。

安装Docker

可以在 Docker 官方页面 ,选择合适的操作系统,然后开始下载。(译者以阿里云ECS-CentOS为例)

OS要求

Docker社区版要求CentOS7以上

卸载旧版本Docker:

$ sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine



安装必要依赖

sudo yum install -y yum-utils device-mapper-persistent-data lvm2
// 设置repositry
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
// 安装Docker引擎社区版
sudo yum install docker-ce docker-ce-cli container.io



上面已经安装好了Docker,但是此时Docker并没有运行

sudo systemctl start docker



检查Docker版本

docker --version
// Docker version 19.03.5, build 633a0ea



验证Docker正常安装:

sudo docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
1b930d010525: Pull complete
Digest: sha256:6540fc08ee6e6b7b63468dc3317e3303aae178cb8a45ed3123180328bcc1d20f
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.



另外输出信息还解释了Docker的执行过程:

To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.



到此我们已经安装好了Docker并尝试了’Hello, World`程序。



查看容器详情:

sudo docker container ls
// 或
sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8e29e1a1f7bc hello-world "/hello" 4 minutes ago Exited (0) 4 minutes ago clever_cerf



该命令会输出所有的容器实例,包括:

  • Container ID

  • Image

  • Command

  • Created

  • Status

  • Ports

  • Names



暂停和删除容器与镜像

$ docker container ls
$ docker container stop webserver
$ docker container ls -a
$ docker container rm webserver
// rm 前需先暂停,否则会导致删除失败
$ docker image ls
$ docker image rm nginx

MacOS安装Docker Desktop

需要先注册一个Docker ID,来确认身份,并且如果要发布镜像到Docker Hub上,也会以该ID上传。建议ID和自己的常用ID保持一致,毕竟这是个人在技术世界遨游的一个品牌。

  1. 下载Desktop: https://download.docker.com/mac/stable/Docker.dmg

  2. 测试安装成与否:

// 拉取示例项目
git clone https://github.com/docker/doodle.git
// 构建镜像
cd doodle/cheers2019 && docker build -t notcoder/cheers2019 .
// 本地运行
docker run -it --rm notcoder/cheers2019
// 发布该镜像
docker login && docker push notcoder/cheers2019

A Docker image is a private filesystem, just for your container. It provides all the files and code your container will need. Running the docker build command creates a Docker image using the Dockerfile. This built image is in your machine's local Docker image registry.

安装Node.js镜像

拉取镜像:

docker pull node
// Using default tag: latest
// latest: Pulling from library/node



国内用户会发现这个巨慢无比,难以忍受,不要慌,阿里云用户可以参考镜像加速器,亲测使用后速度立即改善。



创建一个Node程序http-test.js:

const https = require('https');
https
.get('https://jsonplaceholder.typicode.com/todos/1', response => {
let todo = '';
response.on('data', chunk => {
todo += chunk;
});
response.on('end', () => {
console.log(`The title is "${JSON.parse(todo).title}"`);
});
})
.on('error', error => {
console.error('Error: ' + error.message);
});



这个程序只是简单地使用原声http模块发出一个请求到JSON Placeholder .

通过Docker执行上面程序:

docker run -it --rm --name my-first-node-app -v "$PWD":/usr/src/app -w /usr/src/app node node http-test.js
// output
// The title is "delectus aut autem"



  • -it 在interactive模式下运行容器,可以在其中执行多个命令。

  • —rm 执行完后会自动删除容器。

  • —name [name] 为Docker守护程序中运行的进程提供名称。

  • -v [local-path: docker-path] 在Docker中安装一个本地目录,该目录允许交换信息或访问当前系统的文件系统。

  • -w [docker-path] 设置工作目录(起始路径)。默认情况下是/。

  • node 是要运行的镜像的名称。它总是出现在所有docker run标志之后。

  • node node-test.js是在指定的容器中的执行命令。这些总是位于镜像名称之后。



这样我们不再需要在本地安装node运行时就可以执行上面的简单node程序了。

创建React应用



既然本文是面向前端开发人员的,因此让我们在Docker中创建一个React应用程序。

上面我们已经有了Node镜像,所以可以完全在镜像上运行我们的React应用,不过在此之前先来了解一个相当重要的概念Dockerfile



Dockerfile

本质上,Dockerfile是一个简单的文本文件,其中包含有关如何构建Docker镜像的说明。通常文件中需要指定需要使用的镜像,镜像中应包含的文件目录及构建之前需要执行的命令。

在项目的根目录下创建一个Dockerfile:



# 选择镜像
FROM node
## 在容器中设置环境、安装依赖
COPY package.json ./
ENV NODE_PATH=/node_modules
ENV PATH=$PATH:/node_modules/.bin
RUN yarn config set registry https://registry.npm.taobao.org/
RUN yarn
# Add project files to /app route in Container
ADD . /app
# Set working dir to /app
WORKDIR /app
# expose port 3000
EXPOSE 3000



然后我们就可以创建一个新的镜像,在Dockerfile所在目录下执行:

docker image build -t react-test
// docker build -t react-test
// output
Sending build context to Docker daemon 9.216kB
Step 1/8 : FROM node
---> 7354979df4ec
Step 2/8 : COPY package.json ./
---> 2334ae246c09
Step 3/8 : ENV NODE_PATH=/node_modules
---> Running in a9eef0bd74ee
Removing intermediate container a9eef0bd74ee
---> 6a754f277b15
Step 4/8 : ENV PATH=$PATH:/node_modules/.bin
---> Running in 220b38640a08
Removing intermediate container 220b38640a08
---> 969d68a0dd44
Step 5/8 : RUN yarn
---> Running in f149ebb35477
yarn install v1.21.1



查看构建后的镜像是否成功:

docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
react-test latest 1118cccafb44 9 hours ago 1.25GB
node latest 7354979df4ec 7 days ago 939MB
hello-world latest fce289e99eb9 12 months ago 1.84kB



构建了好的镜像我们可以理解为就是一个已经安装好所有环境且待运行的应用,现在运行一个容器:

docker run -it -p 3000:3000 react-test /bin/bash



通过/bin/bash在运行容器中开启一个交互式的终端,然后我们可以执行命令,如yarn startyarn build。键入exit来退出容器,并且容器中产生的内容变更如生成的build文件夹将不会被保存,但是可以指定-v参数来保存文件,这样当我们执行yarn build后,会在本地创建build目录。



docker run -it -p 3000:3000 -v $(pwd):/app react-test /bin/bash



这样我们就完成了一个React应用的容器化,此时我们可以通过localhost:3000来访问React应用,就跟本地启动该应用一样。



需要注意的是我们本地没有任何关于项目的环境设置,一切都在镜像中,只需要本地有相应代码并且具备一个Dockefile就可以了,Docker可以帮我们实现一个统一的开发及部署环境。



预告:下一篇文章打算使用Docker来构建jenkins,然后通过jenkins来自动化构建我们上面创建的React应用,并实现自动化部署。



参考文档

用户头像

费马

关注

一个想当厨子的程序员@杭州 2018.07.28 加入

公众号:【也寻常】 在杭州的同学,来加个微信吧

评论

发布
暂无评论
译-面向前端开发人员的Docker入门指南