앞선 과정에서 Route53 서비스를 이용해 프로젝트에 도메인을 부여했다.
그러나 해당 도메인에 접근할 때 보니 http 즉, 보안성이 결여된 도메인이었다.

이제 해당 도메인을 https로 만들기 위해 ACM(AWS Certificate Manager)를 사용할 생각이다.

ACM이란?
웹 사이트와 애플리케이션을 보호하는 퍼블릭 및 프라이빗 SSL/TLS X.509 인증서와 키를 만들고, 저장하고, 갱신하는 복잡성을 처리.

이제 사용중인 ECS 서비스에 SSL을 적용해보고자 한다.

인증서 요청

먼저 인증서 요청 페이지에 접근하면 아래와 같은 화면이 나타난다.
퍼블릭 인증서 요청 선택한다.

그 다음 도메인 이름에는 [*.mydomain.com]
위와 같이 나의 도메인을 설정하는데, 맨 앞에 "*."을 붙여준다.


앞선 포스팅에서 서브 도메인을 생성했는데, sub.mydomain.com 이와 같은 형식이었다.
"*."을 붙여주게되면 mydomain 앞에 어떤 서브도메인명이 붙더라도 전부 인증서가 적용된다.

인증서가 생성되고 최초 상태는 검증 대기 중이다.

Route53 연결

[CNAME 이름 / CNAME 값]을 저장해두고 Route53에서 레코드 생성 버튼을 누른다.

그 다음 SSL 인증서 적용을 원하는 도메인을 클릭한 후 레코드를 생성한다.


이 상태로 Route53의 호스팅 영역에서 방금 체크한 도메인 호스팅 영역을 살펴보면
CNAME으로 레코드가 생성되어 있다.

잠시 기다리면 ACM 인증서가 발급 상태로 변경된다.(한 5분 걸리는 듯 하다.)

로드밸런서 리스너 추가

ACM은 로드밸런서를 통해서만 사용이 가능하다.


리스너 및 규칙 우측에 [리스너 추가] 버튼을 누른다.

프로토콜 HTTPS를 추가해주고, 대상 그룹을 지정한다.

다음 스텝으로 보안 정책을 선택하고
Certificate source => ACM으로 선택해준다.
그 후 Certificate => 구매한 도메인을 설정해준다.

잠시 기다리면 SSL/TLS가 적용된다.


도메인 맨 앞에 자물쇠 모양이 생겼으면 성공!

도메인 연결에 앞서 선행되어야 할 것들

  1. 도메인을 보유하고 있어야 한다.
  2. ELB 설정

AWS에서 도메인을 구매할 수 있지만, 연간 12~13 달러를 지불해야한다.
필자는 가비아에서 할인하는 도메인을 구매해 사용할 예정이다.

또한, 개인 도메인 접근은 로드밸런서를 통해 진행되도록 해볼 예정이다.

Route53 개인 도메인 연결


호스팅 생성

먼저 호스팅 영역을 생성한다.


생성시 도메인 이름은 가비아에서 구매한 도메인 이름으로 설정했다.

호스트가 생성되었고, 2개의 레코드가 생겨났다.
유형이 NS인 레코드의 트래픽 라우팅 대상 4개의 값이 필요하다. (ns로 시작하는 값들)

구매한 가비아 도메인에 라우팅 대상 설정

이제 가비아 네임서버 설정 페이지에서 트래픽 라우팅 대상 4개의 값을 입력한다.(맨 뒤에 .은 빼준다.)

서브 도메인 생성

DNS 정보 설정을 마쳤다면, 이제 사용자들이 접근할 서브 도메인을 생성할 차례이다.
서브도메인의 경우 보유한 퍼블릭 IP가 있다면 직접 연결하면 되지만,
앞선 포스팅에서 자동 배포를 구현한 next app을 로드밸런서를 통해 서비스 중이므로 해당 로드밸런서를 통해 생성한다.

레코드 생성을 눌러준다.

서브 도메인 레코드를 설정하고, 별칭 토글을 활성화 시키면 트래픽 라우팅 대상으로 로드밸런서를 설정할 수 있다.

필자는 Application Loadbalancer를 통해 next app의 트래픽을 관리하고 있으므로
[Application/Classic Load Balancer에 대한 별칭]을 설정하고, 리전과 로드밸런서를 선택해주었다.


이제 준비가 끝났다.
도메인 활성화 확인하기
위 사이트에 들어가면 방금 등록한 도메인이 정상적으로 열리는지 확인할 수 있다.
(등록하자마자 활성화 되지는 않는다. 시간이 좀 걸린다…!)


결과

Next 프로젝트에 도메인이 생겼다.
이제 누구든 도메인을 통해 내가 만든 프로젝트에 접근이 가능하다.

ECS 서비스 자동 배포 구현하기 (feat. Git Action)

앞선 포스팅에서 ECS Service 까지 생성을 완료하고 확인까지 마쳤다.
이번에는 Git을 통해 ECS Service 자동 배포를 구현하고자 한다.

Task.json 파일 생성

먼저 서비스 생성에 성공한 Task의 Json을 긁어온다.

태스크 정의 - 태스크를 선택하고 JSON - 클립보드 복사 진행

 

그 다음 프로젝트 루트에 [.ecr] -> [prod] -> [task.json] 파일을 생성한다.

{
  "taskDefinitionArn": "arn:aws:ecs:ap-northeast-2:448648424519:task-definition/sample-next-app:latest",
  "containerDefinitions": [
    {
      "name": "sample",
      "cpu": 0,
      "portMappings": [
        {
          "name": "sample-7000-tcp",
          "containerPort": 7000,
          "hostPort": 7000,
          "protocol": "tcp",
          "appProtocol": "http"
        }
      ],
      "essential": true,
      "environment": [],
      "mountPoints": [],
      "volumesFrom": []
    }
  ],
  "family": "sample-next-app",
  "executionRoleArn": "arn:aws:iam::448648424519:role/ecsTaskExecutionRole",
  "networkMode": "awsvpc",
  "revision": 5,
  "volumes": [],
  "status": "ACTIVE",
  "requiresAttributes": [
    {
      "name": "com.amazonaws.ecs.capability.ecr-auth"
    },
    {
      "name": "ecs.capability.execution-role-ecr-pull"
    },
    {
      "name": "com.amazonaws.ecs.capability.docker-remote-api.1.18"
    },
    {
      "name": "ecs.capability.task-eni"
    }
  ],
  "placementConstraints": [],
  "compatibilities": ["EC2", "FARGATE"],
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "256",
  "memory": "512",
  "runtimePlatform": {
    "cpuArchitecture": "X86_64",
    "operatingSystemFamily": "LINUX"
  },
  "registeredAt": "2023-10-27T01:49:45.973Z",
  "registeredBy": "arn:aws:iam::448648424519:root",
  "tags": []
}

AWS에 있던 Task json에서 containerDefinitions -> image 부분은 삭제한다.
ECR에 Docker Image가 계속 갱신되어서 이미지 버전이 계속 변경되기 때문에 task.json에 고정으로 사용하는건 의미가 없다.

workflow.yml 파일 수정

ECS 자동 배포를 위한 workflow를 추가해준다.

name: Staging # 워크플로 Action의 이름
on:
  push:
    branches: [main] #github main 브런치에 푸시 발생 시 실행 ( main 외 다른브런치 이용시 이름변경)
jobs:
  staging: #staging이라는 작업
    name: deploy to staging # 작업의 이름
    runs-on: ubuntu-latest # 실행될 작업환경을 말함.
    steps:
      - name: Checkout
        uses: actions/checkout@v3 #체크아웃 받기
      - name: HelloWorld
        uses: actions/hello-world-javascript-action@v1 # 헬로월드 찍어보기
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} # Github Secret 이름
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} # Github Secret 이름
          aws-region: ap-northeast-2 # AWS 리전 선택
      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v1
      - name: Build, tag, and push image to Amazon ECR
        id: build-image
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          ECR_REPOSITORY: sample # ecr 이름
          IMAGE_TAG: ${{ github.run_number }} # git 커밋넘버를 이미지 이름 구분을 위해 넣어줌
        run: |
          # Build a docker container and
          # push it to ECR so that it can
          # be deployed to ECS.
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
          echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"
      - name: Fill in the new image ID in the Amazon ECS task definition
        id: task-def
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: .ecs/prod/task.json # task파일
          container-name: sample #이미지 컨테이너 이름
          image: ${{ steps.build-image.outputs.image }}
      - name: Deploy Amazon ECS task definition
        uses: aws-actions/amazon-ecs-deploy-task-definition@v1
        with:
          task-definition: ${{ steps.task-def.outputs.task-definition }}
          service: sample-ecs-service #클러스터 서비스 명
          cluster: sample-cluster # 클러스터 명
          wait-for-service-stability: true

ECS task definition 부분부터 추가해주면 된다.

page.tsx 내용 수정

이제 next app의 내용을 수정해서 자동 배포 후 정상적으로 적용되는지 확인해본다.

export default function Home() {
  return (
    <div>
      <h1>Hello Next.js!</h1>
      <h2>feat. CI/CD with AWS-ECS</h2>
    </div>
  );
}

결과

이로써 ECS 자동배포까지 구현이 완료되었다.

다음 포스팅에서는 Route53으로 그럴싸한 도메인을 붙이는 과정을 진행해보고자 한다.

–끝–

ECS Cluster 생성

Cluster란?
ECS 클러스터는 Docker Container를 실행할 수 있는 논리적인 공간이다.
ECR에 등록한 Docker Image를 가지고 컨테이너를 구성하려면 이 클러스터를 생성 및 사용해야 한다.

클러스터 이름을 sample-cluster로 짓고, 나머지 설정은 그대로 둔 후 생성한다.

인프라 탭에서 주로 Fargate와 EC2 인스턴스 둘을 사용한다.
간략하게 두 인프라의 차이점을 살펴보면 아래와 같다.


EC2인스턴스
EC2는 AWS에 대표적인 서비스 중 하나이다. 주로 서버로 사용하며, 비용을 지불하고 가상의 서버를 대여 받을 수 있다.

ECS 서비스를 구축할 때 EC2 인스턴스를 인프라로 선택하면 서비스에 속한 EC2 인스턴스 서버와 클러스터를 직접 관리해주어야 한다.

Fargate
EC2 인스턴스와 다르게 서버 인스턴스를 관리할 필요가 없는 컨테이너 서비스이며 사용량에 따라 요금이 부과되는 종량제 형식으로 제공된다.
(서버리스란 서버가 없다는 것이 아니다. 서버가 필요한 순간이 왔을 때 잠시 서버를 깨워 기능을 수행하고 다시 잠든다. 이렇게 종량제 서비스가 되는 것이다.)

EC2 인스턴스와 Fargate는 상황에 맞게 잘 고려해서 선택하면 될 것 같다.


Task 정의 생성

다시 본론으로 돌아와서 클러스터를 생성했다면, 이제 Task 정의를 생성한다.

클러스터를 생성할 때 인프라를 Fargate로 생성했으니 시작 유형을 AWS Fargate로 설정한다.
태스크 크기는 CPU : 0.25vCPU, 메모리 : 0.5GB 으로 설정한다. (캡처와 다르니 참고)

컨테이너 이름은 sample로 지었다.
이미지 URI는 지난번 ECR에 등록된 이미지 URI를 복사해서 사용한다.
여기서 주의할 점이 있는데, 레포지토리 URI가 아닌 이미지 URI를 복사해야한다.
(그래야 sample:${version}까지 복사된다.)


다음, 포트 매핑에서는 컨테이너 포트를 7000으로 설정한다.
Docker File에서 Port를 7000으로 설정했기 때문에 여기서도 맞춰준다.

이후에는 기본 값으로 두고 작업을 생성한다.


서비스 생성

앞서 클러스터와 Task를 정의 한 것은 바로 서비스를 생성하기 위함이다.
이제 대망의 서비스를 올려보자!

생성한 ECS 클러스터를 클릭하면 서비스 생성이 가능하다.


컴퓨팅 옵션 : 시작 유형
시작 유형 : Fargate
플랫폼 버전 : LATEST



태스크 : 2 (Fargate 인스턴스가 2개 생성된다.)



네트워킹은 별도로 건들지 않았다.
로드밸런서 및 대상 그룹은 서비스를 생성하며 함께 생성해준다.


서비스가 정상적으로 생성되고 활성화가 되었다.

이제서야 비로소 개인 프로젝트가 모든 서버 인스턴스에 Docker를 통한 동일한 서비스 환경을 구축한 것이다.

아래 로드밸런서 DNS 이름의 주소를 가지고 웹에서 나의 프로젝트를 확인할 수 있다.

결과 화면


마무리하며

포스팅을 하면서 서버와 네트워크에 대해 점점 친숙해지는 기분이다.
사실 여기까지의 과정에서 우여곡절이 많았지만 시간이 걸려도 해내면 그만이다.

다음 포스팅에서는 Git을 통한 ECS 서비스 자동 생성을 구현해볼 예정이다.

글을 읽으시는 모든 분들께 알량한 나의 지식이 도움이 되었으면 한다.

AWS - ECR 레포지토리 생성

ECR 레포지토리를 생성해준다.

우선은 연습용으로 사용할 것이기 때문에 프라이빗으로 생성하고, 레포지토리 이름은 "sample"로 지정했다.

docker file 작성

(docker를 미리 설치해주세요 ^^)
이제 ECR 레포지토리를 생성했으니, 해당 레포에 도커 이미지를 등록하기 위해 dockerfile을 만들어준다.
(도커파일 만드는 방법)
(본인의 프로젝트에 맞게 작성하면 된다.)
이번 Next sample 프로젝트를 docker image로 만들기 위해 아래와 같이 작성한다.

FROM node:18-alpine

WORKDIR /app

COPY package.json ./

RUN npm install

#프로젝트의 모든 파일을 복사
COPY . .

RUN npm run build

#포트 7000번 사용
EXPOSE 7000

CMD ["npm", "run", "start"]

github workflow 수정

작성한 docker file을 기반으로 AWS-ECR에 docker image를 자동으로 push할 수 있도록 workflow.yml을 수정한다.

name: Staging # 워크플로 Action의 이름
on:
  push:
    branches: [main] #github main 브런치에 푸시 발생 시 실행 ( main 외 다른브런치 이용시 이름변경)
jobs:
  staging: #staging이라는 작업
    name: deploy to staging # 작업의 이름
    runs-on: ubuntu-latest # 실행될 작업환경을 말함.
    steps:
      - name: Checkout
        uses: actions/checkout@v3 #체크아웃 받기
      - name: HelloWorld
        uses: actions/hello-world-javascript-action@v1 # 헬로월드 찍어보기
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} # Github Secret 이름
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} # Github Secret 이름
          aws-region: ap-northeast-2 # AWS 리전 선택
      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v1
      - name: Build, tag, and push image to Amazon ECR
        id: build-image
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          ECR_REPOSITORY: sample # ecr 이름
          IMAGE_TAG: ${{ github.run_number }} # git 커밋넘버를 이미지 이름 구분을 위해 넣어줌
        run: |
          # Build a docker container and
          # push it to ECR so that it can
          # be deployed to ECS.
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
          echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"

name : Build, tag, and push image to Amazon ECR << 이 부분부터 추가했다.

Git Action / ECR Repository 확인

이제 작성한 docker file과 github workflow를 커밋 & 푸시하여 git action을 통한 docker image 자동 배포를 확인해볼 차례이다.

필자는 workflow의 run 부분을 잘못하여 좀 돌아왔지만 결국 성공했다.

AWS - ECR에도 정상적으로 Image가 push되었다.


마무리하며

이번 포스팅으로 ECR에 docker image를 자동 배포하는 과정을 알아보았다.
여기까지만 해도 기본적인 docker 및 AWS에 대한 지식이 필요하기 때문에 순탄치만은 않았던 것 같다.

다음 포스팅에서는 대망의 ECS 연동 및 자동배포를 다룰 예정이다. (제일 어려운 부분이 될 것 같다.)

화이팅…!!

이번에는 Git - AWS ECS 서비스를 연동해보고자 한다.
(AWS 계정이 필요하다.)


AWS - IAM 설정

AWS - IAM 페이지에서 사용자 생성을 진행한다.

그 다음 액세스 키를 발급한다.

AWS CLI 이용할 예정이기 때문에 아래와 같이 선택한다.

AccessKey를 발급 받으면

[AccessKey, SecretAccessKey]

두 개가 발급되는데, 어디다가 저장해두자.


Git repository - AccessKey 등록

이제 발급 받은 AccessKey와 SecretAccessKey를 Next 프로젝트 레포지토리에 등록해야 한다.

AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY 를 각각 등록해준다.


Next.js 프로젝트 workflow 수정

방금 추가한 Access, Secret 키를 프로젝트 내 github / workflow 파일에 추가해준다.
그래야 해당 키를 가지고 AWS와 연동할 수 있게 된다.

변경사항을 push하여 Git Action을 확인해보도록 하자.

현재는 AccessKey를 설정하는 단계에서 그쳤지만, workflow에 다른 AWS 서비스를 사용할 수 있도록 steps를 추가한다면, 해당 키가 잘 설정되어야만 오류 없이 배포가 된다.


IAM 권한 설정

이제 AWS로 프로젝트를 배포할 모든 서버에 동일한 환경을 구축하기 위해 Docker Image 생성 및 해당 Image의 Repository 역할을 하는 ECR 서비스를 사용할 예정이다.

그러나 해당 작업에 앞서 ECR과 같은 AWS 서비스를 바로 사용할 수는 없다.
우리는 앞선 과정에서 IAM 그룹 or 사용자를 생성하였고 각 서비스에 맞는 권한을 설정해주어야 한다.
필자는 그룹 단위로 권한을 부여하고, 해당 그룹에 속한 사용자들에게 동일한 권한을 부여해주는 방식으로 진행하려고 한다.

IAM 그룹에 권한 설정

그룹에 권한을 추가하려면 [사용자 그룹 - 권한 추가 - 정책 연결]
사용자별 권한을 추가하려면 [사용자 - 권한 추가 - 정책 연결]을 통해 권한을 추가할 수 있다.

필자는 아래와 같이 추가하였다.
아래 빨간 박스를 제외한 다른 권한들은 AWS에 이미 존재하는 권한들이고
빨간 박스는 별도로 추가해주었다.

ecs-cicd-demo-role 추가 방법 (이름은 마음대로 지어주세요)
[사용자 or 사용자 그룹 - 권한 추가 - 인라인 정책 생성 - 정책편집기 JSON] 선택 후 아래 JSON 붙여넣기

{
    "Version": "2012-10-17",
    "Statement":
    [
        {
            "Effect": "Allow",
            "Action":
            [
                "iam:PassRole"
            ],
            "Resource": "arn:aws:iam::*:role/ecsTaskExecutionRole"
        }
    ]
}

그 다음 정책의 이름을 설정해주면 끝이다.

결론적으로 추가한 정책들은 아래와 같다.

//ECR에 대한 모든 권한
AmazonEC2ContainerRegistryFullAccess

//ECS에 대한 모든 권한
AmazonECS_FullAccess

//ECR Public에 대한 모든 권한
AmazonElasticContainerRegistryPublicFullAccess

//S3에 대한 모든 권한
AmazonS3FullAccess

//ECS 클러스터로 애플리케이션 배포를 관리할 때 사용되는 권한
AWSCodeDeployRoleForECS

//AWSCodeDeployRoleForECS와 동일한 목적이지만 최소한의 권한만 부여
AWSCodeDeployRoleForECSLimited

//ECR 컨테이너 빌드를 위한 EC2 프로필을 나타내는 역할
EC2InstanceProfileForImageBuilderECRContainerBuilds

//ELB에 대한 모든 권한
ElasticLoadBalancingFullAccess

//ECS에서 실행 중인 Task에 대한 IAM 역할. 컨테이너 실행 및 관련 작업을 수행 - 별도로 직접 추가 필요
ecs-cicd-demo-role

ECR 관련 workflow 추가 및 배포 확인

이제 github workflow 하단에 ECR 로그인 관련 코드를 추가해준다.

name: Staging # 워크플로 Action의 이름
on:
  push:
    branches: [main] #github main 브런치에 푸시 발생 시 실행 ( main 외 다른브런치 이용시 이름변경)
jobs:
  staging: #staging이라는 작업
    name: deploy to staging # 작업의 이름
    runs-on: ubuntu-latest # 실행될 작업환경을 말함.
    steps:
      - name: Checkout
        uses: actions/checkout@v3 #체크아웃 받기
      - name: HelloWorld
        uses: actions/hello-world-javascript-action@v1 # 헬로월드 찍어보기
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} # Github Secret 이름
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} # Github Secret 이름
          aws-region: ap-northeast-1 # AWS 리전 선택
        #AWS - ECR
      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v1

추가 성공!


정리

  1. AWS의 서비스들을 사용하기 위해서는 IAM 사용자 혹은 사용자 그룹을 생성한다.
  2. IAM 사용자 혹은 사용자 그룹에 AccessKey, SecretAccessKey를 발급 받아 github repository에 등록 및 workflow에 설정한다.
  3. 필요한 AWS 서비스를 사용하기 위해 그에 맞는 권한을 설정한다.
  4. AWS ECR 관련 workflow를 설정한다.

다음 포스팅에서는 본격적으로 ECR, ECS 서비스를 사용해볼 예정이다.
처음이라면 이 모든 과정이 쉽지 않겠지만 천천히 공부하다보면 언젠가는 될 것이라 믿는다.

Docker란 무엇인가?

Docker는 컨테이너화 기술을 사용하여 애플리케이션을 개발, 배포 및 실행하는 데 사용되는 오픈 소스 플랫폼 및 생태계이다. Docker를 사용하면 애플리케이션과 그 종속성을 컨테이너라고 하는 경량 가상 환경에 패키징할 수 있으며, 이러한 컨테이너는 호스트 시스템과 독립적으로 실행다.

Docker의 주요 특징과 개념

  1. 컨테이너: Docker 컨테이너는 애플리케이션, 라이브러리 및 종속성을 패키징하는 데 사용되는 경량 환경이다. 각 컨테이너는 격리된 환경에서 실행되며 호스트 시스템과 공유 커널을 사용한다.

  2. 이미지: Docker 컨테이너를 생성하기 위한 템플릿으로서, 이미지는 애플리케이션과 해당 종속성을 포함한다. 이미지는 컨테이너를 여러 환경에서 생성하고 실행하는 데 사용된다.

  3. 도커 엔진: Docker 엔진은 컨테이너를 관리하고 실행하는 핵심 구성 요소이다. Docker 엔진은 Docker 데몬 및 Docker CLI(Command Line Interface)를 포함하며 컨테이너 작업을 제어한다.

  4. 이식성: Docker 컨테이너는 호스트 환경과 독립적이므로 어디에서나 실행할 수 있다. 이는 개발 환경에서 프로덕션 환경으로 애플리케이션을 이동할 때 매우 유용하다.

  5. 자동화: Docker를 사용하면 애플리케이션의 빌드, 배포 및 스케일링을 자동화할 수 있다. Docker Compose 및 Kubernetes와 같은 도구를 통해 애플리케이션 스택을 정의하고 관리하는 데 도움을 준다.

  6. 확장성: Docker 컨테이너는 가벼우면서 확장 가능하므로 대규모 애플리케이션 배포 및 관리에 적합하다.

Docker는 개발자, 운영팀 및 DevOps 엔지니어 등에게 애플리케이션 배포 및 관리를 단순화하고 효율적으로 관리할 수 있는 강력한 도구이다. 컨테이너화 기술은 애플리케이션의 일관성, 이식성 및 확장성을 향상시키는 데 도움이 된다.


Docker 사용법

Docker의 동작 순서

DockerFile : Container를 어떻게 만들어야 하는지에 대한 설명서 느낌이다.

Image : Docker 파일을 가지고 만들 수 있다.

Container : Image를 고립된 환경(개별적인 FileSystem 안에서) 에서 실행할 수 있는 단위


주요 인스트럭션

FROM : base image를 지정. 주로 OS 이미지나 런타임 이미지를 지정

RUN : 이미지를 빌드할 때 사용되는 커맨드를 설정할 때 사용

ADD : 이미지에 호스트의 파일이나 폴더를 추가하기 위해 사용.
만약 이미지에 복사하려는 디렉토리가 존재하지 않으면 docker가 자동으로 생성

COPY : 호스트 환경의 파일이나 폴더를 이미지 안으로 복사하기 위해 사용
'ADD'와 동일하게 동작하지만 가장 확실한 차이점은
URL을 지정하거나, 압축파일을 자동으로 풀지 않음

EXPOSE : 이미지가 통신에 사용할 포트를 지정할 때 사용

ENV : 환경 변수를 지정할 때 사용
여기서 설정한 변수는 $name, ${name}의 형태로 사용 가능
추가로 아래와 같은 문법으로 사용할 수 있음
- ${name:-else} : name이 정의가 안되어 있다면 'else'가 사용됨

CMD : 도커 컨테이너가 실행될 때 실행할 커맨드를 지정
'RUN'과 유사하지만 CMD는 도커 이미지를 빌드할 때 실행되는 것이 아니라
컨테이너를 시작할 때 실행된다는 것이 다름

ENTRYPOINT : 도커 이미지가 실행될 때 사용되는 기본 커맨드를 지정 (강제)

WORKDIR : RUN, CMD, ENTRYPOINT 등을 사용한 커맨드를 실행하는 디렉토리를 지정
-w 옵션으로 오버라이딩 할 수 있음

VOLUME : 퍼시스턴스 데이터를 저장할 경로를 지정할 때 사용
호스트의 디렉토리를 도커 컨테이너에 연결
주로 휘발성으로 사용되면 안되는 데이터를 저장할 때 사용

DockerFile 생성

FROM node:18-alpine

WORKDIR / app

COPY package.json package-lock.json ./

RUN npm ci

COPY routes/index.js .

ENTRYPOINT [ "node", "index.js" ]

DockerFile 설명

코드 설명 하기 전에 알아둘 점
도커는 레이어 시스템을 차용했기 때문에 빈번하게 발생하는 작업은 아래쪽에 작성해준다.
그러면 가장 빈번한 작업은 레이어의 제일 위쪽에 위치하게 된다.
이미지를 만들 때 변경된 사항부터 이후 단계들에 대해서만 새로 만들고 변경이 없는 레이어는 캐시된 데이터를 그대로 사용한다.
이게 무슨 말인가 하면, 위 코드 맨 첫 줄부터 Layer0 ~ Layer5가 되며, index.js 파일이 변경 되면 이미지를 만들 때 Layer4, 5만 새로 작성한다는 의미이다.
따라서 Docker File을 잘 작성하면 이미지 생성시 불필요한 작업을 줄여 성능을 개선시킬 수 있다.

  • FROM node:18-alpine
    => 베이스 이미지를 설정한다. node의 경우는 전용 베이스 이미지를 지원하기 때문에 node:[version] 형식으로 설정한다.

  • WORKDIR / app
    => root 경로에 있는 app이라는 디렉토리에 우리 프로젝트에 관련된 모든 파일들을 copy해오겠다라는 뜻.

  • COPY package.json package-lock.json ./
    => 프로젝트에 필요한 모듈들에 대한 정보가 들어 있는 package 파일을 copy한다.

  • RUN npm install or ci
    => package.json / package-lock.json에 설정된 모듈을 설치한다.
    => npm install을 사용할 경우 특정 라이브러리에서 ‘버전 몇 이상은 다 괜찮다’ 라고 명시를 해주면 최신 버전이 나올 때마다 해당 버전을 새로 설치한다. 그러나 ci를 사용하면 package-lock.json에 설정된 버전 그대로 설치한다.

  • COPY index.js
    => index.js 파일을 copy한다.

  • ENTRYPOINT [”node”, “index.js”]
    => node를 실행하고, index.js를 실행한다.

Docker File로 Image 및 Container 만들기

Docker build

$docker build -f Dokcerfile -t today-lunch .

위 명령어를 해석하면 아래와 같다.
docker build - 말 그대로 도커를 빌드한다는 뜻.
-f Dockerfile - Dockerfile이라는 파일명을 가진 DockerFile을 명시한다.

만약 도커파일명이 다르다면 -f [도커파일명]을 작성한다.
-t image name - 도커이미지의 이름을 부여
위 명령어가 제대로 실행되면 도커 이미지가 생성된다.

Docker Image 생성

docker images

이미지에 대한 정보를 확인할 수 있다.

Docker Container 실행

docker run -d -p 8080:8080 today-lunch

-d (detached) - 컨테이너를 백그라운드에서 실행하겠다는 의미
-p (port 지정) - host machine의 포트 8080과 container의 포트 8080을 연결해주는 작업

컨테이너 정보 확인

docker ps

Next.js 프로젝트 생성

설치 및 실행

vscode를 열고 원하는 폴더에 접근한 후 다음 명령어를 실행한다.

$npx create-next-app

globals.css 파일에서 tailwind CSS 관련된 설정만 남겨두고 나머지는 전부 삭제한다.
page.tsx에서도 “Hello Next.js!” 라는 문구만 작성한다.

$npm run dev

위 명령어를 실행해서 정상적으로 웹 페이지가 열리는지 확인한다.


Github workflow 작성

생성한 Next.js 프로젝트 최상단에 다음과 같은 폴더 및 파일을 추가한다.

  1. .github
  2. .github/workflows
  3. .github/workflows/workflow.yml

이후 workflow.yml 파일에 다음과 같은 내용을 추가한다.

name: Staging # 워크플로 Action의 이름
on:
  push:
    branches: [main] #github main 브런치에 푸시 발생 시 실행 ( main 외 다른브런치 이용시 이름변경)
jobs:
  staging: #staging이라는 작업
    name: deploy to staging # 작업의 이름
    runs-on: ubuntu-latest # 실행될 작업환경을 말함.
    steps:
      - name: Checkout
        uses: actions/checkout@v3 #체크아웃 받기
      - name: HelloWorld
        uses: actions/hello-world-javascript-action@v1 # 헬로월드 찍어보기

git에 push하여 Action이 잘 동작하는지 확인한다.

커밋 메세지가 이상하지만 Action은 정상적으로 동작한다!


다음 포스팅에서는 AWS 연동을 진행할 예정이다.
AWS에서 제공하는 다양한 서비스에 대해 가능하면 최대한 짚어볼 예정이다.

Next.js 샘플 프로젝트를 Git Workflow / Action을 통해 AWS ECS로 자동 배포하는 시스템을 구축해보려 한다.


자동 배포 sequence

아래와 같은 순서를 거쳐 최종적으로 AWS ECS에 프로젝트가 자동 배포되는 과정을 경험해보고자 한다.

  1. Next.js 프로젝트 생성 및 배포
  2. Git workflow 작성
  3. AWS ECS 서비스에 연동

uml diagram

선행되어야 할 학습 내용

  • Next.js 설치 및 프로젝트 생성
  • Git / Github - workflow 설정과 Git Action
  • AWS
    • Route53 - 도메인 호스팅
    • EC2 - 클라우드 인스턴스
    • Load Balancer - 인스턴스에 접근할 트래픽 분산 처리
    • ECR - Docker Image의 저장소
    • ECS - ECR에 저장된 Docker Image를 기반으로 인스턴스를 생성하는 서비스
  • Docker - 배포한 시스템이 모든 환경에서 동일할 수 있도록 컨테이너라는 청사진 역할을 하는 시스템 구축 환경 제공

+ Recent posts