ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • ALB(https) - ECS Fargate(Nginx - Django) 배포하기
    공부/AWS 2023. 4. 12. 00:45

    AWS는 여러가지 시행착오를 겪게한다. 나도 많은 블로그를 찾아보고 봤지만 내가 직접 해보면서 해결을 하는게 최고로 도움이 되고 살이된다고 생각한다. 누군가에게 이 글이 도움이 될 수 도 있고 불친절하다고 느낄 수 있지만, 천천히 풀지 못했던 문제를 해결하면 충분히 쉽게 해결 할 수 있을 것이다. 
    나는 배포는 하는 과정에서 많은 에러를 겪었지만 생각나는 부분들은 기록을 하려고 한다. 
    해당 글에선 Django 코드나 설정을 잘 했다고 생각하고 AWS 관련된 부분만 설명을 하려고 합니다.
    도커 컴포즈로 작성을 먼저 해봤던 사람이라면 빠르게 이해 하실거라고 생각합니다.


    * 프로젝트 구조

    nginx, docker-entrypoint.sh,  docker-compose, 설정파일이 모두 base에서 시작한다고 생각해주면 좋을 거 같다. 

    nginx는 폴더를 새로 하나 만들어서 그 안에 nginx.dockerfile, nginx.conf 파일을 가지고 있다. 

     

     

    1. ECR에서 Repo 만들기

    ECR 생성시 어떤 설정을 따로 하지 않았다. 레포 생성 버튼을 클린한 후 프라이빗으로 설정하고 레포지토리 이름에는 내가 생각하는 이름을 넣어주면 된다. 나같은 경우 django/ nginx라고 이름을 정하였다.
    태그 변경 불가능, 푸시할 때 스캔, KMS 암호 모두 비활성화로 레포를 생성하였다.

     

     

    2. AWS Configure 등록( 참고 블로그 )

    configure를 등록해야 ECR에 image를 push 할 수 있다. AWS에서 우측 상단에 자신의 계정을 누르면 밑에 이미지처럼 보일 것이다.

    보인다면 보안 자격증명을 선택한다.

    보안자격증명 클릭
    액세스 키 만들기 클릭

    하단으로 내리다 보면 액세스키 만들기가 있는데 이곳에서 액세스키를 만들어서 잘 가지고 있자!!!!(중요)

    이제 AWS CLI를 install 해야 한다.( 자신의 환경에 맞게 설치 하기를 바랍니다./ AWS 주소)

     

    Command Line Interface - AWS CLI - AWS

    aws-shell은 명령줄 셸 프로그램으로서, AWS 명령줄 인터페이스를 사용하는 새로운 사용자와 고급 사용자 모두에게 도움이 되는 편의 기능 및 생산성 기능을 제공합니다. 주요 기능은 다음과 같습

    aws.amazon.com

    설치가 완료 되었다면 aws configure로 발급받은 AWS Access Key id, AWS Secret Access key를 입력한다.
    (Region은 자신의 Region으로 서울이면 ap-northeast-2, output은 json)

     

     

    3. docker-compose.yml 작성

    # ---------ECS------------
    version: "3"
    
    services:
      nginx:
        build:
          context: ./nginx/
          dockerfile: nginx.Dockerfile
        image: {aws계정}.dkr.ecr.{rigion}.amazonaws.com/nginx:latest
        container_name: nginx
        ports:
          - "80:80"
        depends_on:
          - django
        links:
          - django
      django:
        build:
          context: .
          dockerfile: Dockerfile
        image: {aws계정}.dkr.ecr.{rigion}.amazonaws.com/django:latest
        container_name: django
        entrypoint:
          - ./docker-entrypoint.sh

    - 기존 doker-compose랑은 비슷하면 조금은 다릅니다. network 설정이나 env, volume을 설정해주지 않아도 됩니다.

    - image에는 ECR 만들면 레포를 클릭하고 푸시명령 보기를 클릭

    - "빌드가 완료되면 이미지에 태그를 지정하여 이 리포지토리에 푸시할 수 있습니다" 말 밑에 있는 명령어를 복사해서 image에 넣는다.
    (ex. 1111222233334444.dkr.ecr.ap-northeast-2.amazonaws.com/nginx:latest 를 image에 넣어주세요)

    - "인증 토큰을 검색하고 레지스트리에 대해 Docker 클라이언트를 인증합니다." 말 밑에 있는 명령어는 8번에서 사용 할꺼니깐 기억해두거나 복사해두자!!!!!

     

     

    4. Dockerfile 작성

    FROM --platform=linux/amd64 python:3.9.13
    ENV PYTHONUNBUFFERED=1
    
    COPY . /app
    WORKDIR /app
    COPY requirements.txt /app/
    
    RUN pip3 install --upgrade pip && pip3 install -r requirements.txt
    
    COPY docker-entrypoint.sh /app/
    RUN chmod +x /app/docker-entrypoint.sh
    ENTRYPOINT ["/app/docker-entrypoint.sh"]

    - FROM 에서 --platform을 사용하는 이유는 맥북으로 개발하면 ECS에서 서비스를 실행할 때 정상 작동이 되지 않는 문제를 해결하기 위해서 작성하였습니다. 해당 상태로 build하면 docker desktop에서 컨테이너로 만들어서 확인해보면 amd64를 확인 할 수 있습니다.

    - 장고 app을 실행할 수 있도록 구성하였습니다. chmod +x는 스크립트에 실행 권한을 주기위함입니다.

     

     

    5. docker-entrypoint.sh

    #!/bin/bash
    
    # Make Migrations Database
    python3 manage.py makemigrations --settings=config.settings.prod --noinput
    
    # Migrate Database
    python3 manage.py migrate --settings=config.settings.prod --noinput
    
    # Collect Staticfiles
    python3 manage.py collectstatic --settings=config.settings.prod --noinput
    
    echo "from django.contrib.auth import get_user_model; User = get_user_model(); User.objects.create_superuser('example@qwer.com', 'admin', 'example')" | python3 manage.py shell --settings=config.settings.prod
    
    # Run Gunicorn (WSGI Server)
    gunicorn --bind 0.0.0.0:8000 config.wsgi.prod:application

    - echo를 하는 이유는 관리자 계정을 생성하기 위함입니다. 

    - WSGI로 Gunicorn 서버를 실행하였습니다.

     

     

    6. nginx.dockerfile 작성

    FROM --platform=linux/amd64 public.ecr.aws/nginx/nginx
    # Configure Nginx
    COPY ./nginx.conf /etc/nginx/nginx.conf

    - 기존 Docker hub에 있는 nginx를 사용해서 컨테이너를 만들고 시도를 했지만 AWS에서 제가 생각한대로 작동하지 않고 컨테이너 생성에서 오류가 계속 발생해서 AWS gallery에서 이미지를 사용할 수 있도록 변경 하였습니다.

    - nginx에는 설정을 default.conf가 아닌 nginx.conf에 설정 하였습니다.

     

     

    7. nginx.conf 작성

    worker_processes auto;
    events { worker_connections 1024; }
    http {
    
        upstream django {
            ip_hash;
            server localhost:8000; 
        }                          
    
        server {
            listen 80;	# IPv4 setting
            server_name  example.com;
    
            location /static/ {
                proxy_pass http://django;
                proxy_set_header Host $http_host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
                proxy_set_header X-Forwarded-Ssl $https;
            }
    
            location /media/ {
                alias   https://{bucket-name}.s3.{region}.amazonaws.com/{path};
            }
    
    
            location / {
                proxy_pass http://django;
                proxy_set_header Host $http_host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
                proxy_set_header X-Forwarded-Ssl $https;
            }
    
            location /health-check {
                proxy_pass http://django/health-check;
            }
        }
    }

    - static은 s3에서 사용을 하지않고 ECS django 컨테이너에서 사용하려고 생각하여 설정을 location / 과 동일하게 하였습니다.

    - media는 이미지를 업로드하고 관리하기 위하여 s3에 버킷을 만들고 등록하였습니다.

    - location / 은 기본 설정을 한 후 proxy_pass로 upstream에 전달하여 django 컨테이너를 바라볼수있도록 하였습니다.

    - health-check는 타겟그룹(대상그룹)에서 return 200을 받기위해서 django api에 health-check 기능을 만들었습니다.(그래서 proxy pass도 upstream을 바라보고 마지막 경로를 health-check로 지정해 주었습니다.)

    - upstream에서 localhost로 지정한건, 여러가지 테스트(컨테이너명, 서비스명 등) host를 찾을수 없었고, 같은 호스트 영역에서 실행을 한다면 localhost로 지정하면 경로를 확인 할 수 있다는 것을 알고 localhost:8000으로 하였습니다.(8000은 Gunicorn 실행 포트입니다.)

    - 내부 통신은 http로 하기 때문에 https로 설정하지 않았습니다.

    - https는 ALB에서 적용을 하기 때문에 nginx를 private subnet에서 실행하면 https로 설정하지 않아도 됩니다.(EC2에서 실행한다면 SSL 부분을 추가해줘야합니다.)

     

    8. nginx.conf 작성

    - 이제 모든 설정을 마쳤기 때문에 이미지를 빌드하고 push하면 된다.

    - push 하기 전에 아까 3번 설명에서 마지막에 말했던 복사했던 부분(ECR 푸시명령보기)를 터미널에 입력

    - "Login Succeeded"라는 문구가 보이면 로그인에 성공한 것이다.(안된다면 AWS configure에 입력했던 값에 오류가 없는지 확인)

    - docker-compose build 로 이미지를 빌드하자.

    (만약 docker-compose파일이 ecs-docker-compose.yml라면 docker-compose ecs-docker-compose.yml build 로 입력하자!!!)

    - 이미지 빌드가 정상적으로 됐다면, docker-compose push 명령어를 실행하자.

    (ecs-docker-compose.yml라면 docker-compose ecs-docker-compose.yml push로 입력)

     

    9. Task 정의

    AWS ECS -> 테스크 정의 -> (우측) 새 테스크 정의 클릭

     

    - 정의 패밀리는 편하게 이름이라고 생각하자

    - 컨테이너 이름은 자유롭게 지어도 된다. 하지만 알아 볼 수 는 있도록 하자

    - URI는 push했던 ECR repo에 가면 복사 할 수 있다. ( private registry는 설정 안해도 됩니다.)

    - 따로 추가해줄 부분은 없습니다.

    - 만약 nginx.conf 에서 listen을 다르게 하셨다면 컨테이너 포트도 그에 맞게 설정해주시면 됩니다.

    - 컨테이너 추가를 해서 django 컨테이너 생성을 할 수 있도록 설정합니다.(필수컨테이너 로 하세요~)

    - Gunicorn 서버 포트를 8000으로 설정하였으니 컨테이너 포트도 동일하게 설정합니다.

    - 만약 VPC endpoint를 사용해서 private subnet에서 ECS Fargate를 실행하고 싶으시다면 추후에 링크로남겨서 설정하는 방법을 설명하도록 하겠습니다.(S3 endpoint를 사용하시려면 환경변수를 꼭 지정하세요.)

    - 환경변수 입력시 대문자로 입력하시기 바랍니다.

    - 태스크 크기는 조절을 할 수 있으므로 처음에는 작게 서비스 하는 것이 좋다고 생각합니다.(저는 0.5vCPU, 1GB로 했습니다.)

    - 태스크 역할은 밑에서 정의해드리겠습니다.

    - 스토리지, 모니터링은 따로 어떤부분을 설정하거나 하시지 않으셔도 됩니다.

     

     

    10. IAM 정의

     

    - IAM에 접속 (역할 선택)

    - elastic container service 선택

    - service task 선택

    - AmazonECSTaskExecutionRolePolicy 를 선택

    - 역할 이름을 지정해 주면 IAM에 역할을 사용할 수 있습니다.

     

     

    11. ALB 생성

    EC2 -> 로드밸런서 선택 -> 로드밸런서 생성 클릭

    ALB(Application Load Balancer) 선택

     

    - 이름 설정, 인터넷 경계로 설정

    - IPv4로 설정

    - 사용할 VPC 선택 

    - 가용영역은 ECS Cluster에서 사용할 private subnet과 동일한 public subnet으로 설정해야 합니다.

    - 즉, public subnet 선택

    - 보안그룹에서 기존에 설정하신게 있으시다면 상관없지만, 없으시다면 해당 방법으로 생성하시면 됩니다.

    - 인바운드 규칙을 https, http로 설정하고, anywhere-IPv4로 설정합니다.

    - 만약 https를 사용 안하신다면 http로 해주시면 됩니다. (Route 53부분은 추후에 링크로 남기겠습니다.)

     

    - 리스너는 ALB로 들어오는 프로토콜과 포트를 지정해 주는 부분입니다.

    - 현재 80으로 설정한 것과 같은 방식으로 프로토콜은 https, 포트는 443으로 지정해줍니다.

    - 대상그룹은 새롭게 생성하도록 하겠습니다.

    - 대상유형은 IP주소로 설정

    - ECS 와 연결이 될 대상그룹이므로 nginx를 바라 볼 수 있도록 포트는 80으로 설정합니다.

    - 상태 검사는 nginx에서 django를 바라볼 수 있도록 API를 만들었기 때문에 저같은 경우 경로를 /health-check로 설정하였습니다.

    - 이후 대상그룹에서 특별한 설정 없이 생성을 하고 로드밸런서와 연결을 해준 후 로드밸런서 생성을 하시면 로드밸런서 생성이 마무리 됩니다.

     

    12. ECS Cluster 생성 및 서비스 생성

    - 클러스터 생성시 우선 퍼블릭 서브넷으로 생성을 하시고 테스트 해보시길 바랍니다.

    - private 서브넷으로 설정을 하시고 바로 하셔서 접속이 안되시면 어떤부분에서 오류가 나는지 정확하지 않기 때문입니다.

    - 저 같은 경우 Public으로 테스트 후  VPC Endpoint를 사용해서 ECS를 Private Subnet에서 사용할 수 있도록 하였습니다.

    * 클러스터 생성에서는 ALB에서 선택한 AZ 연결된 subnet으로 클러스터를 생성해주세요!!!

     

    클러스터 생성 -> 클러스터 클릭 -> 서비스에서 생성 클릭

    - 시작유형으로 선택

    - 애플리케이션 유형은 서비스로 선택

    - 패밀리는 이전에 태스크 정의에서 만들었던 태스크를 선택

    - 서비스 이름 정의

    - 원하는 태스크를 2개로 지정하시면 하나의 서브넷에서 2개의 태스크가 작동한다고 보시면 됩니다.

     

    일부러 필드 값을 제거하였습니다.

    - 네트워킹에서 public으로 확인해보시고 싶으시다면 public subnet으로 설정하신 후 퍼블릭 ip는 켜짐으로 해줘야 합니다.

    - private subnet은 퍼블릭 IP는 꺼짐으로 해줘야합니다.

    - 보안그룹은 대상그룹에서 80으로 전달 받을 것이기 때문에 80포트로 인바운드 할 수 있는 보안그룹을 새로 만들어 주시면됩니다.

     

    로드 밸런싱에서는 이전에 만들었던 로드밸런싱으로 연결하고 대상그룹도 동일하게 지정해줍니다.

     

    이후 생성을 해주시면 서비스가 생성이 되면서 태스크 카테고리에서 새로운 태스크가 실행이 되고 있는 것을 확인 하실 수 있으실겁니다.

     

    !!!!! 주의할 점

    1. public으로 먼저 접근 할 수 있는지 확인

    2. 컨테이너 생성시 꼭 에러 잘 확인해보기

    3. 컨테이너 설정에 문제가 없다면 aws 설정들을 잘 확인해 보자.

     

    - 어떤 문제를 해결하기 위해 검색하고 블로그에 작성한 글입니다. 부족한점이 많지만 틀린점이나 부족한점이 있다면 말씀해주시면 감사하겠습니다.

     

     

    Ref.

     

    https://it-eldorado.tistory.com/166

     

     

    [AWS] Docker 기반의 ECS로 Django, Gunicorn, Nginx 배포하기

    근무 중인 회사에서 서버 배포 방식을 변경하는 중대한 업무를 맡게 되면서, Docker를 공부하고 또 이를 활용한 배포 서비스인 ECS에 대해서도 공부하게 되었다. 물론 Docker 기반의 ECS 서비스에 실

    it-eldorado.tistory.com

    https://wooono.tistory.com/133

     

    [AWS ECS] ECS(Elastic Container Service) 란?

    ECS란? Docker는 최근 각광 받고 있는 컨테이너 기술이다. 하지만 Docker를 이용해 서비스를 구축 하려면 여러가지 고려 해야할 사항이 많다. 따라서 필연적으로 컨테이너를 적절하게 배치하고 관리

    wooono.tistory.com

    https://dev.classmethod.jp/articles/contaier-doceker-and-ecs-for-beginner-kr/

     

    초심자도 이해하는 컨테이너 도커 ECS | DevelopersIO

    안녕하세요 클래스메소드의 수재입니다. 이번에 ECS에 관한 영상을 찍게 되어 그 내용을 블로그에 미리 정리해보고자 합니다. ECS라는 서비스가 있는 것도 알고 많이 쓰고 있다는 것도 알고 있지

    dev.classmethod.jp

     

    댓글

Designed by Tistory.