뒤로
Jihwan
Jihwan ·

CI/CD에 대해 공부해보자 - 3. Docker&AWS

저번 포스트에서 test를 어떻게 하는지 알아봤으니 이제 배포를 해보겠다. 배포에 필요한 서버는 AWS의 ec2인스턴스를 사용하였다.

처음에 말한 github action을 이용해서 CD를 구현할건데 기본적인 flow는 이렇다 (출처 까먹었다)

deployment_flowchart.png

github action (.yml에 정의됨)=> 소스코드 image를 build -> dockerhub에 push -> ec2서버에 접속해서 image pull -> pull 한 image로 container run

이런 식으로 굴러가게 된다

다음은 작성한 .yml, dockerfile, nginx.conf파일이다. 아 nginx.conf은 Django의 static이랑 media 파일들을 특정 포트에 serve해주기 위해서 사용했다. 이걸 안하면 templates에 static 파일 안에 js파일들이 적용이 안 된다..

.yml

name: Django Tests

on:
  push:
    branches:
      - main
      - test
      - depy
  pull_request:
    branches:
      - main

jobs:
  test:
    runs-on: ubuntu-latesta

    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: '3.11'

    - name: Install dependencies
      run: |
        python -m venv venv
        source venv/bin/activate
        pip install django

    - name: Change directory
      run: |
        source venv/bin/activate
        python -m pip install Pillow
        cd SOS
        python manage.py makemigrations question
        python manage.py migrate
        python manage.py test

  deploy:
      runs-on: ubuntu-latest
      needs: test
  
      steps:
      - name: Checkout code
        uses: actions/checkout@v4
  
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2
  
      - name: Log in to Docker Hub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}
  
      - name: Build and push Docker image
        run: |
          cd SOS
          docker build -t sos_init .
          docker tag sos_init ${{ secrets.DOCKER_USERNAME }}/sos:latest
          docker push ${{ secrets.DOCKER_USERNAME }}/sos:latest
  
      - name: Set up SSH
        uses: webfactory/ssh-agent@v0.5.3
        with:
          ssh-private-key: ${{ secrets.EC2_PRIVATE_KEY }}
  
      - name: Deploy to EC2
        run: |
          ssh -o StrictHostKeyChecking=no ec2-user@***.ap-northeast-2.compute.amazonaws.com << 'EOF'
            docker pull ${{ secrets.DOCKER_USERNAME }}/sos:latest
            docker stop django_sos || true
            docker rm django_sos || true
            docker run -d --name django_sos -p 80:80 -e DJANGO_SETTINGS_MODULE=SOS.settings ***/sos:latest
          EOF

밑에 docker run~부분을 보면 -p 80:80이 있는데 저게 호스트의 80포트를 컨테이너의 80포트와 맵핑시키는 역할이다.

http -> 80포트

https -> 443포트

Dockerfile(requirements.txt안에 필요한 dependencies들이 들어있다)

FROM python:3.11.9
WORKDIR /SOS

COPY . /SOS/.

#Dependencies setting
RUN pip install --no-cache-dir -r requirements.txt
RUN apt-get update && apt-get install -y nginx

ENV DJANGO_SETTINGS_MODULE=SOS.settings
ENV PYTHONUNBUFFERED 1

COPY nginx.conf /etc/nginx/sites-available/default
RUN rm -f /etc/nginx/sites-enabled/default && ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled
RUN python manage.py collectstatic --noinput

CMD service nginx start && \ 
    python manage.py makemigrations question && \
    python manage.py migrate && \
    python manage.py load_questions && \ 
    gunicorn --bind 0.0.0.0:8000 SOS.wsgi:application

EXPOSE 80

필요한 dependency들을 깔아주고, 저 collectstatic은 내가 setting.py에 정의한 경로대로 (지금은 static파일) 정적파일을 자동으로 수집해준다.

밑에 CMD부분은 컨테이너가 실행될 때 자동으로 실행해주는 CLI명령어다. database build와 맨 밑에 gunicorn이 있는데 production할 때는 runserver가 아닌 저 명령어로 실행하는 것이 좋다고 한다 (애초에 runserver은 개발 단계에서 사용하기 위해 만들어졌다고 한다).

가장 밑에는 EXPOSE 80이 있는데 저것이 container의 80포트를 외부에 노출시킨다는 것이다.

nginx.conf

server {
    listen 80;
    server_name localhost;

    location /static/ {
        alias /SOS/static/;
    }

    location /media/ {
        alias /SOS/media/;
    }

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $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;
    }
}

nginx가 뭔지 하나도 몰라서 조금 고생했는데(아직도 모름..) 80포트로 들어온 요청 중 url 경로에 media와 static들을 포함한 요청은 파일dir을 맵핑시켜서 처리하고 나머지 요청은 8000포트에서 실행 중인 server에 전달한다는 거 같다.

사실 아직 정리되지 않은 부분이 많은데(event trigger, 도메인 연결..) 마지막 최종 발표 전에 시간이 있으면 정리해야겠다.

정말 배포에 대한 기본지식이 너무 없어서 시간을 꽤나 많이 잡아먹었다. aws는 정말 한번 제대로 공부해봐야겠다. CI/CD 끝!

2

댓글

로그인 후 댓글을 남길 수 있습니다.

아직 댓글이 없습니다.