AWS: 단일 EC2 인스턴스의 여러 컨테이너 간 통신

10509 단어 ecsawsdockerec2

동기 부여:



때로는 서비스가 단일 애플리케이션이 아니므로 도커화 및 배포가 쉽습니다. 하지만 서비스에 여러 개의 도커 컨테이너가 있고 그 중 하나가 다른 컨테이너의 데이터를 소비한다면 어떻게 될까요? 이를 위해서는 컨테이너 간에 일종의 통신 채널을 만들어야 합니다. 애플리케이션당 EC2 인스턴스를 생성할 때 전략으로 쉽게 달성할 수 있지만 이렇게 하면 비용이 증가하고 분명히 그러한 전략은 비용 효율적이지 않습니다. 그런 다음 EC2 인스턴스를 최대한 활용하고 단일 EC2 인스턴스에서 도커화된 두 애플리케이션을 모두 실행하려고 합니다.

이것은 애플리케이션이 있고 단일 EC2 인스턴스에서 이들 간에 통신할 수 있는 기능이 있는 2개의 도커 컨테이너로 구성된 AWS ECS 작업 정의를 생성하는 방법에 대한 단계별 안내서입니다.



EC2 인스턴스에서 도커 컨테이너를 관리하기 위해 ECS service을 사용할 예정입니다.

ECS 클러스터 및 ECS 서비스 생성



거의 수정하지 않고 공식 AWS-ECSexample의 기본 스택부터 시작하겠습니다.

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에 연결된 도커 컨테이너 간의 통신을 가능하게 합니다.

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


ProducerApp 컨테이너 추가



이제 생산자 컨테이너를 추가해 보겠습니다. 생산자 응용 프로그램은 소비자가 데이터를 얻을 수 있는 끝점이 /data인 포트 8080의 간단한 HTTP 서버입니다.

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


소비자 컨테이너 추가



또한 소비자 컨테이너를 추가해 보겠습니다. 소비자 응용 프로그램은 매분 생산자 응용 프로그램에서 데이터를 검색하는 HTTP 클라이언트처럼 작동할 수 있는 기능이 있는 포트 8081의 HTTP 서버입니다.

그러나 소비자 응용 프로그램이 생산자 응용 프로그램에 도달하는 방법을 어떻게 알 수 있습니까? 소비자 앱은 어떤 엔드포인트를 핑해야 합니까? 우리는 잠시 후에 이것을 명확히 할 것입니다.

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에 추가하여 컨테이너가 별칭을 사용하여 서로 통신할 수 있도록 하고 두 컨테이너가 동일한 브리지 네트워크에 있으므로 컨테이너에 연결할 수 있습니다.

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


우선 우리는 두 개의 도커 컨테이너가 실행되고 있음을 분명히 알 수 있습니다. 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"}


그것은 매력처럼 작동했습니다! 이제 소비자 응용 프로그램의 HTTP 클라이언트에 대한 대상 끝점으로 producerContainer:8080/data를 추가하고 생산자 응용 프로그램에서 데이터를 검색하기만 하면 됩니다!

추가 아이디어로, 데이터를 더 자주 검색하거나 컨테이너 간의 양방향 통신이 필요한 경우 컨테이너 간에 WebSocket 연결을 설정하고 보다 편리하고 빠른 방식으로 데이터를 생성/소비하는 것을 고려할 수 있습니다!

결론:



이 트릭은 docker 및 AWS에 대해 더 많이 이해하는 데 도움이 될 뿐만 아니라 더 많은 EC2 인스턴스를 활용하고 비용을 절약하는 데 도움이 됩니다! 당신이 그것을 즐겼기를 바랍니다!

좋은 웹페이지 즐겨찾기