网络研讨会系列:建筑容器应用

网络研讨会系列

本文补充了关于在云中部署和管理容器化工作负载网络研讨会系列 本系列介绍了容器的基本知识,包括容器生命周期管理,部署多容器应用程序,扩展工作负载以及理解Kubernetes,以及突出显示运行有状态应用程序的最佳实践。

本教程包含系列“构建容器化应用程序”第二部分中介绍的概念和命令。

介绍

在上一篇教程“ 如何安装和配置Docker”中 ,我们探讨了将Docker容器转换为Docker镜像的一种方法。 尽管我们使用的方法起作用,但并不总是构建图像的最佳方式。

在很多情况下,您需要将现有代码放入容器图像中,并且需要一个可重复的一致机制来创建与最新版本的代码库同步的Docker图像。

Dockerfile通过提供构建Docker镜像的声明式和一致的方式来满足这些要求。

另外,您有时候会想要集成整个应用程序,这些应用程序由多个部署和管理在一起的异构容器组成。

Docker Compose与Dockerfile一样,采用声明式的方法为您提供一个定义整个技术的方法,包括网络和存储需求。 这不仅使构建容器化应用程序变得更容易,而且还使管理和扩展变得更容易。

在本教程中,您将使用基于Node.jsMongoDB的示例Web应用程序从Dockerfile构建Docker镜像,您将创建一个允许Docker容器进行通信的自定义网络,并且您将使用Docker Compose来启动和规模容器化的应用程序。

先决条件

要学习本教程,您将需要:

第1步 - 使用Dockerfile构建映像

首先转到您的主目录,然后使用GitGitHub上的官方存储库克隆本教程的示例Web应用程序。

cd ~
git clone https://github.com/janakiramm/todo-app.git

这会将示例应用程序复制到名为todo-app的新目录中。

切换到todo-app并使用ls来查看目录的内容。

cd todo-app
ls

新目录包含两个子目录和两个文件:

  • app - 示例应用程序源代码的存储目录
  • compose - Docker Compose配置文件存储的目录
  • Dockerfile - 一个包含用于构建Docker镜像的指令的文件
  • README.md - 一个包含示例应用程序的单句汇总的文件

运行cat Dockerfile向我们展示了以下内容:

〜/待办事项应用内/ Dockerfile
FROM node:slim
LABEL maintainer = "jani@janakiram.com"
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY ./app/ ./
RUN npm install
CMD ["node", "app.js"]

让我们来更详细地看看这个文件的内容:

  • FROM表示您正在构建自定义图像的基础图像。 在此示例中,映像基于node:slim ,一个公共Node.js映像 ,其中只包含运行node所需的最小程序包。
  • LABEL是通常用于添加描述性信息的关键值对。 在这种情况下,它包含维护者的电子邮件地址。
  • RUN执行容器内的命令。 这包括通过运行基本的Linux命令创建目录和初始化容器等任务。 该文件中的第一个RUN命令用于创建保存源代码的目录/usr/src/app
  • WORKDIR定义了执行所有命令的目录。 它通常是代码复制的目录。
  • COPY将主机上的文件复制到容器图像中。 在这种情况下,您正在将整个app目录复制到图像中。
  • 第二个RUN命令执行npm install来安装package.json定义的应用程序依赖项。
  • CMD运行将保持容器运行的过程。 在这个例子中,你将使用参数app.js执行node

现在是时候从Dockerfile构建图像了。 使用-t开关标记与注册表用户名,图像名称和一个可选标记的图像。

docker build -t sammy/todo-web .

输出确认图像已Successfully built并进行适当标记。

Output from docker build -tSending build context to Docker daemon  8.238MB
Step 1/7 : FROM node:slim
 ---> 286b1e0e7d3f
Step 2/7 : LABEL maintainer = "jani@janakiram.com"
 ---> Using cache
 ---> ab0e049cf6f8
Step 3/7 : RUN mkdir -p /usr/src/app
 ---> Using cache
 ---> 897176832f4d
Step 4/7 : WORKDIR /usr/src/app
 ---> Using cache
 ---> 3670f0147bed
Step 5/7 : COPY ./app/ ./
 ---> Using cache
 ---> e28c7c1be1a0
Step 6/7 : RUN npm install
 ---> Using cache
 ---> 7ce5b1d0aa65
Step 7/7 : CMD node app.js
 ---> Using cache
 ---> 2cef2238de24
Successfully built 2cef2238de24
Successfully tagged sammy/todo-web:latest

我们可以通过运行docker images命令来验证docker images

docker images

在这里,我们可以看到图像的大小以及创建后的时间。

Output from docker imagesREPOSITORY                                       TAG                 IMAGE ID            CREATED             SIZE
sammy/todo-web                                   latest              81f5f605d1ca        9 minutes ago       236MB

因为我们还需要一个MongoDB容器来运行示例Web应用程序,所以让我们把它交给我们的机器。

docker pull mongo:latest

输出报告确切地说哪个图像与下载状态一起被拉动。

Output from docker pulllatest: Pulling from library/mongo
Digest: sha256:18b239b996e0d10f4ce2b0f64db6f410c17ad337e2cecb6210a3dcf2f732ed82
Status: Downloaded newer image for mongo:latest

我们现在拥有运行示例应用程序所需的所有东西,所以让我们创建一个允许我们的容器相互通信的自定义网络。

第2步 - 创建一个网络链接容器

如果我们要通过docker run命令独立启动Web应用程序和数据库容器,他们将无法找到对方。

要查看原因,请查看Web应用程序的数据库配置文件的内容。

cat app/db.js

在导入Mongoose (一个用于Node.js的MongoDB对象建模库)并定义了一个新的数据库模式之后 ,Web应用程序尝试连接到主机名为db的数据库,该数据库尚不存在。

〜/待办事项应用内/应用/ db.js
var mongoose = require( 'mongoose' );
var Schema   = mongoose.Schema;

var Todo = new Schema({
    user_id    : String,
    content    : String,
    updated_at : Date
});

mongoose.model( 'Todo', Todo );

mongoose.connect( 'mongodb://db/express-todo' );

为了确保属于同一应用程序的容器相互发现,我们需要在同一个网络上启动它们。

除了安装期间创建的默认网络, Docker还提供了创建自定义网络的功能。

您可以使用以下命令检查当前可用的网络:

docker network ls

每个由Docker创建的网络都基于一个驱动程序 在下面的输出中,我们看到名为bridge的网络是基于驱动bridge local范围表示网络仅在此主机上可用。

Output from docker network lsNETWORK ID          NAME                DRIVER              SCOPE
5029df19d0cf        bridge              bridge              local
367330960d5c        host                host                local
f280c1593b89        none                null                local

我们现在将为我们的应用程序创建一个名为todo_net的自定义网络,然后我们将在该网络上启动容器。

docker network create todo_net

输出告诉我们所创建的网络的散列。

Output from docker network createC09f199809ccb9928dd9a93408612bb99ae08bb5a65833fefd6db2181bfe17ac

现在,再次列出可用的网络。

docker network ls

在这里,我们看到todo_net已经可以使用了。

Output from docker network lsNETWORK ID          NAME                DRIVER              SCOPE
c51377a045ff        bridge              bridge              local
2e4106b07544        host                host                local
7a8b4801a712        none                null                local
bc992f0b2be6        todo_net            bridge              local

当使用docker run命令时,我们现在可以使用--network开关来引用这个网络。 让我们启动具有特定主机名的Web和数据库容器。 这将确保容器可以通过这些主机名相互连接。

首先,启动MongoDB数据库容器。

docker run -d \
--name=db \
--hostname=db \
--network=todo_net \
mongo

仔细看看这个命令,我们看到:

  • -d开关在分离模式下运行容器。
  • --name--hostname开关将一个用户定义的名称分配给容器。 --hostname开关也添加一个入口到由Docker管理DNS服务 这有助于通过主机名解析容器。
  • --network开关指示Docker引擎在自定义网络上启动容器,而不是默认网桥。

当我们看到一个很长的字符串作为docker run命令的输出时,我们可以假定容器已经成功启动了。 但是,这可能不能保证容器实际运行。

Output docker runaa56250f2421c5112cf8e383b68faefea91cd4b6da846cbc56cf3a0f04ff4295

通过docker logs命令验证db容器已启动并正在运行。

docker logs db

这将容器日志打印到stdout 日志的最后一行表示MongoDB已经准备就绪, waiting for connections

Output from docker logs2017-12-10T02:55:08.284+0000 I CONTROL  [initandlisten] MongoDB starting : pid=1 port=27017 dbpath=/data/db 64-bit host=db
. . . .
2017-12-10T02:55:08.366+0000 I NETWORK  [initandlisten] waiting for connections on port 27017

现在,我们启动Web容器并验证它。 这一次,我们还包括--publish=3000:3000 ,它将主机的端口3000到容器的端口3000

docker run -d \
--name=web \
--publish=3000:3000 \
--hostname=web \
--network=todo_net \
sammy/todo-web

你会像以前一样收到一个很长的字符串。

我们来验证一下这个容器是否正常运行。

docker logs web

输出证实Express (我们的测试应用程序所基于的Node.js框架)正在listening on port 3000

Output from docker logsExpress server listening on port 3000

验证Web容器是否能够通过ping命令与db容器进行通信。 我们通过在连接到伪TTY( -t )的交互式( -i )模式下运行docker exec命令来执行此操作。

docker exec -it web ping db

该命令生成标准的ping输出,并让我们知道这两个容器可以相互通信。

Output from docker exec -it web ping dbPING db (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: icmp_seq=0 ttl=64 time=0.210 ms
64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.095 ms
...

CTRL+C停止ping命令。

最后,通过将Web浏览器指向http://your_server_ip:3000来访问示例应用程序。 您将看到一个带有标签的网页,该标签读取容器待办事项示例以及接受待办事项任务作为输入的文本框。

为了避免命名冲突,现在可以停止容器并使用docker rmdocker network remove命令清理资源。

docker rm -f db
docker rm -f web
docker network remove todo_net

在这一点上,我们有一个容器化的Web应用程序,由两个独立的容器组成。 下一步,我们将探索一个更强大的方法。

第3步 - 部署多容器应用程序

尽管我们能够启动链接容器,但它并不是处理多容器应用程序的最优雅的方式。 我们需要一个更好的方式来声明所有相关的容器并将它们作为一个逻辑单元进行管理。

Docker Compose是开发人员可用于处理多容器应用程序的框架。 像Dockefile一样,这是一个定义整个的声明机制。 我们现在将我们的Node.js和MongoDB应用程序转换成一个基于Docker Compose的应用程序。

从安装Docker Compose开始。

sudo apt-get install -y docker-compose 

让我们来看一下示例web应用程序的compose目录中的docker-compose.yaml文件。

cat compose/docker-compose.yaml

docker-compose.yaml文件将所有内容结合在一起。 它定义了db: block中的MongoDB容器,web db: block中的Node.js Web容器,以及networks: block中的自定义网络。

请注意, build: ../. 指令,我们指向编写到app目录中的Dockerfile 这将指示Compose在启动Web容器之前构建图像。

〜/待办事项应用内/撰写/搬运工-compose.yaml
version: '2'
services:
  db:
    image: mongo:latest
    container_name: db
    networks:
      - todonet
  web:
    build: ../.
    networks:
      - todonet
    ports:
     - "3000"
networks:
  todonet:
    driver: bridge

现在,转到compose目录并使用docker-compose up命令启动应用程序。 docker run-d开关以分离模式启动容器。

cd compose
docker-compose up -d

输出报告Docker Compose创建了一个名为compose_todonet的网络,并在其上启动了两个容器。

Output from docker-compose up -dCreating network "compose_todonet" with driver "bridge"
Creating db
Creating compose_web_1

请注意,我们没有提供显式的主机端口映射。 这将迫使Docker Compose分配一个随机的端口来暴露主机上的Web应用程序。 我们可以通过运行以下命令找到该端口:

docker ps

我们看到Web应用程序暴露在主机端口32782

Output from docker psCONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                     NAMES
6700761c0a1e        compose_web         "node app.js"            2 minutes ago       Up 2 minutes        0.0.0.0:32782->3000/tcp   compose_web_1
ad7656ef5db7        mongo:latest        "docker-entrypoint..."   2 minutes ago       Up 2 minutes        27017/tcp                 db

通过浏览您的Web浏览器来验证这个http://your_server_ip:32782 这将启动Web应用程序,就像您在第2步结束时看到的一样。

随着我们的多容器应用程序通过Docker Compose运行,让我们来看看管理和扩展我们的应用程序。

第4步 - 管理和缩放应用程序

Docker Compose可以轻松扩展无状态Web应用程序。 我们可以用一个命令启动我们的web容器的10个实例。

docker-compose scale web=10

输出让我们看到正在创建和实时启动的实例。

Output from docker-compose scaleCreating and starting compose_web_2 ... done
Creating and starting compose_web_3 ... done
Creating and starting compose_web_4 ... done
Creating and starting compose_web_5 ... done
Creating and starting compose_web_6 ... done
Creating and starting compose_web_7 ... done
Creating and starting compose_web_8 ... done
Creating and starting compose_web_9 ... done
Creating and starting compose_web_10 ... done

通过运行docker ps验证Web应用程序是否被缩放到10个实例。

docker ps

请注意,Docker已经分配了一个随机的端口来暴露主机上的每个web容器。 任何这些端口都可以用来访问应用程序。

Output from docker psCONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                     NAMES
cec405db568d        compose_web         "node app.js"            About a minute ago   Up About a minute   0.0.0.0:32788->3000/tcp   compose_web_9
56adb12640bb        compose_web         "node app.js"            About a minute ago   Up About a minute   0.0.0.0:32791->3000/tcp   compose_web_10
4a1005d1356a        compose_web         "node app.js"            About a minute ago   Up About a minute   0.0.0.0:32790->3000/tcp   compose_web_7
869077de9cb1        compose_web         "node app.js"            About a minute ago   Up About a minute   0.0.0.0:32785->3000/tcp   compose_web_8
eef86c56d16f        compose_web         "node app.js"            About a minute ago   Up About a minute   0.0.0.0:32783->3000/tcp   compose_web_4
26dbce7f6dab        compose_web         "node app.js"            About a minute ago   Up About a minute   0.0.0.0:32786->3000/tcp   compose_web_5
0b3abd8eee84        compose_web         "node app.js"            About a minute ago   Up About a minute   0.0.0.0:32784->3000/tcp   compose_web_3
8f867f60d11d        compose_web         "node app.js"            About a minute ago   Up About a minute   0.0.0.0:32789->3000/tcp   compose_web_6
36b817c6110b        compose_web         "node app.js"            About a minute ago   Up About a minute   0.0.0.0:32787->3000/tcp   compose_web_2
6700761c0a1e        compose_web         "node app.js"            7 minutes ago        Up 7 minutes        0.0.0.0:32782->3000/tcp   compose_web_1
ad7656ef5db7        mongo:latest        "docker-entrypoint..."   7 minutes ago        Up 7 minutes        27017/tcp                 db

您也可以使用相同的命令来缩放Web容器。

docker-compose scale web=2

这一次,我们看到额外的实例被实时删除。

Output from docker-composeStopping and removing compose_web_3 ... done
Stopping and removing compose_web_4 ... done
Stopping and removing compose_web_5 ... done
Stopping and removing compose_web_6 ... done
Stopping and removing compose_web_7 ... done
Stopping and removing compose_web_8 ... done
Stopping and removing compose_web_9 ... done
Stopping and removing compose_web_10 ... done

最后,重新检查实例。

docker ps

输出确认只剩下两个实例。

Output from docker psCONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                     NAMES
36b817c6110b        compose_web         "node app.js"            3 minutes ago       Up 3 minutes        0.0.0.0:32787->3000/tcp   compose_web_2
6700761c0a1e        compose_web         "node app.js"            9 minutes ago       Up 9 minutes        0.0.0.0:32782->3000/tcp   compose_web_1
ad7656ef5db7        mongo:latest        "docker-entrypoint..."   9 minutes ago       Up 9 minutes        27017/tcp                 db

您现在可以停止应用程序,并且像以前一样,还可以清理资源以避免命名冲突。

docker-compose stop
docker-compose rm -f
docker network remove compose_todonet

结论

本教程向您介绍了Dockerfiles和Docker Compose。 我们以Dockerfile作为构建图像的声明机制,然后探讨了Docker网络的基础知识。 最后,我们使用Docker Compose来扩展和管理多容器应用程序。

要扩展您的新设置,您可以添加在另一个容器中运行的Nginx反向代理,以将请求路由到其中一个可用的Web应用程序容器。 或者,您可以利用DigitalOcean的块存储负载均衡器 ,为容器式应用带来持久性和可扩展性。

赞(52) 打赏
未经允许不得转载:优客志 » 系统运维
分享到:

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏