动机:

有时您的服务不是单个应用程序,它很容易 dockerize 和部署。但是,如果您的服务有多个 docker 容器,其中一个使用另一个容器的数据怎么办?为此,您需要在容器之间创建某种通信通道。当您为每个应用程序创建一个 EC2 实例时,可以通过策略轻松实现,但这会增加您的成本,显然这样的策略并不划算。然后,您想充分利用 EC2 实例并在单个 EC2 实例上运行两个 dockerized 应用程序。

这是有关如何创建 AWS ECS 任务定义的分步指南,该定义由两个带有应用程序的 docker 容器组成,并且能够在单个 EC2 实例上在它们之间进行通信。

[目标CDK](https://res.cloudinary.com/practicaldev/image/fetch/s--rscttXKb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https:// /dev-to-uploads.s3.amazonaws.com/uploads/articles/lww72taa5mrs684dp72y.png)

我们将使用ECS 服务来管理 EC2 实例上的 docker 容器。

创建ECS集群&ECS服务

让我们从官方 AWS-ECS示例的基本堆栈开始,稍作修改。

declare const vpc: ec2.Vpc;

// Create an ECS cluster
const cluster = new ecs.Cluster(this, 'Cluster', {
  vpc,
});

// Add capacity to it
cluster.addCapacity('DefaultAutoScalingGroupCapacity', {
  instanceType: new ec2.InstanceType("t2.micro"),
  desiredCapacity: 1,
});

// Place for adding task definition,
// docker container options,
// and all other options from this article below

// Instantiate an Amazon ECS Service
const ecsService = new ecs.Ec2Service(this, 'Service', {
  cluster,
  taskDefinition,
});

进入全屏模式 退出全屏模式

添加任务定义

这里主要是用**Bridge Network Mode**创建任务定义。这种模式使得连接到同一个 Docker 内部网络或 Bridge 的 docker 容器之间的通信成为可能。

const taskDefinition = new ecs.Ec2TaskDefinition(this, 'TaskDef', {
  networkMode: Network.BRIDGE,
});

进入全屏模式 退出全屏模式

添加ProducerApp容器

现在让我们添加生产者容器。生产者应用程序将是一个简单的 HTTP 服务器,端口为 8080,具有/data端点,消费者可以在其中获取数据。

const producerContainer = taskDefinition.addContainer('ProducerContainer', {
  image: ecs.ContainerImage.fromRegistry('producer-image'),
  memoryLimitMiB: 256,
});
producerContainer.addPortMappings({
   containerPort: 80,
   hostPort: 8080,
   protocol: ecs.Protocol.TCP,
});

进入全屏模式 退出全屏模式

添加消费者容器

另外让我们添加消费者容器。消费者应用程序将是端口 8081 上的 HTTP 服务器,能够像 HTTP 客户端一样工作,每分钟从生产者应用程序检索数据。

但是消费者应用程序如何知道如何联系生产者应用程序呢? Consumer App 应该 ping 哪个端点?我们稍后会澄清这一点。

const consumerContainer = taskDefinition.addContainer('ConsumerContainer', {
  image: ecs.ContainerImage.fromRegistry('consumer-image'),
  memoryLimitMiB: 256,
});
consumerContainer.addPortMappings({
   containerPort: 81,
   hostPort: 8081,
   protocol: ecs.Protocol.TCP,
});

进入全屏模式 退出全屏模式

添加容器间通信

现在是最后一个技巧:我们需要在 ProducerContainer 和 ConsumerContainer 之间创建一种通信方式。我们将使用addLink方法。这种方法的好处是,我们不需要担心映射端口或其他任何事情。在内部,此方法向 /etc/hosts 添加了一个别名,它允许容器仅使用别名相互通信,并且您还记得这两个容器都在同一个 Bridge Network 中,因此它使容器可以访问。

consumerContainer.addLink(producerContainer)

进入全屏模式 退出全屏模式

从CDK的角度来看就是这样。但是我们仍然缺少生产者的端点,消费者应用程序应该从那里检索数据。

深入寻找Producer端点

成功部署 CDK 后,我们来看看 Producer 端点的样子。

通过 SSH 或会话管理器连接到 EC2 实例。

~$ sudo docker ps -a
CONTAINER ID   IMAGE                  COMMAND                  CREATED       STATUS     PORTS     NAMES
d6a008b35bb2   producerContainer      "/usr/src/app/produc…"   10 min ago   Up 10 min             producerContainer
a85bbfa3fae3   consumerContainer      "/usr/src/app/consum…"   10 min ago   Up 10 min             consumerContainer

进入全屏模式 退出全屏模式

首先,我们可以清楚地看到两个 docker 容器都已启动并正在运行。让我们深入了解 consumerContainer。

~$ sudo docker exec -it a85bbfa3fae3 /bin/sh
~$ cat /etc/hosts
127.0.0.1   localhost
::1         localhost ip6-localhost ip6-loopback
172.17.0.2  producerContainer d6a008b35bb2
172.17.0.3  a85bbfa3fae3

进入全屏模式 退出全屏模式

如您所见,现在我们知道了 producerContainer 的别名:

172.17.0.2 producerContainer d6a008b35bb2.

让我们从中获取一些数据!

~$ curl producerContainer:8080/data
~$ {data: "Very important data"}

进入全屏模式 退出全屏模式

它就像一个魅力!现在您只需添加producerContainer:8080/data作为 Consumer Application 的 HTTP 客户端的目标端点,并从 Producer Application 中检索数据!

另外,如果你更频繁地获取数据,或者你需要容器之间的双向通信,可以考虑在容器之间建立WebSocket连接,以更方便、更快捷的方式生产/消费数据!

结论:

这个技巧不仅可以帮助您更多地了解 docker 和 AWS,还可以利用更多的 EC2 实例并为您节省一些钱!希望你喜欢它!

Logo

云原生社区为您提供最前沿的新闻资讯和知识内容

更多推荐