[0712] AWS로 Docker 배포

nikevapormax·2022년 7월 12일
1

TIL

목록 보기
70/116
post-thumbnail

Docker

AWS ec2

ec2 생성하기

  • 배포를 하기 위해 먼저 ec2를 생성해준다.
  • 프리 티어인 Amazon Linux 2 AMI (HVM) - Kernel 5.10, SSD Volume Type를 사용해 ec2를 생성하도록 하자.
  • 프리 티어를 선택해주면 된다. 그리고 검토 및 시작을 누른다.
  • 보안 그룹을 편집해주도록 하자.
  • 아래와 같이 80 포트를 세팅하고, 검토 및 시작을 누른다.
    • 우리가 배포할 웹서비스에 접근할 수 있도록 미리 열여두는 것이다. 사용자는 프론트를 통해서 접근하므로 http의 기본 포트인 80을 열어주는 것이다.
  • 이전에 받아서 사용하던 키페어를 삭제해버렸기 때문에, 새로운 키페어를 다운받았다. 만약 사용하던 키페어가 있다면 굳이 새로 생성하지 않아도 무방하다.
  • 아래 링크가 걸려있는 곳을 누르면 내가 생성한 ec2 인스턴스의 상태를 볼 수 있는 창으로 이동하게 해준다.
  • ec2의 상태가 실행중으로 되어 있어야 배포가 가능하다.

keypair 권한 변경하기

  • 아까 발급받은 키페어의 권한을 변경해보도록 하겠다.
  • change mode의 약자인 chmod와 소유주만 읽고 쓸 수 있게 해주는 600을 사용하도록 하겠다.
$ chmod 600 ~{keypair 위치}
  • -i옵션을 통해 키페어로 접근하며, ec2의 퍼블릭 ip 주소를 넣어주면 된다.
$ ssh -i ~/.ssh/sparta-docker.pem ec2-user@{public_ip}
  • 위의 두 코드를 모두 작성하게 되면 아래와 같은 결과화면이 나오게 된다.

ec2에 docker 설치하기

  • amazon linux docker install와 같은 검색어를 통해 구글링해주면 되고, 나는 amazon 공홈에서 정보를 찾아보았다.
  • 스크롤을 내리다 보면 Amazon Linux 2에 Docker 설치라는 탭을 발견할 수 있는데, 이곳에 있는 내용을 토대로 터미널로 가 docker를 설치해주면 된다.
    • yum : amazon linux에서 패키지를 관리하는 cli 툴
$ sudo yum update -y                          <<< 새로 업데이트된 것이 있는지 확인 
$ sudo amazon-linux-extras install docker -y  <<< 도커 설치

  • Docker 서비스 실행하기
$ sudo service docker start
  • Docker 상태 확인하기
$ service docker status

  • docker가 실행되고 있으니, docker ps를 통해 정보를 확인하려 하면 아래와 같이 권한이 없다고 나온다. 이유는 현재 ec2 유저에서 docker를 실행할 권한이 없어서 그런 것이다.
  • 아래 코드로 권한을 부여할 수 있다.
$ sudo usermod -a -G docker ec2-user

  • 해당 권한이 반영된 shell을 사용하려면 exit 명령어를 통해 한 번 나갔다 다시 들어와야 한다.
  • 다시 들어와 docker ps 쳐보면 돌아가고 있는 것은 없지만 아래와 같이 확인할 수 있다. 이렇게 되면 docker 설치는 끝났다.

docker-compose 설치하기

  • 아래 코드를 통해 설치할 수 있다.
    • uname에 다른 값을 넣을 필요없이 아래 코드 그대로 넣어주면 된다.
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.29.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose

  • 이렇게 한 뒤 터미널에 docker-compose를 입력하면 설명창이 쭈룩 나오는데, 이러면 잘 설치된 것이다.

docker-compose.yaml 만들기

  • 아래의 명령어를 입력해 수정창을 열어준다.
    • vi : 쉘스크립트에서 파일을 생성하거나 조작하게 해주는 툴
$ vi docker-compose.yaml

  • 위의 화면이 보이면 a를 입력해준다. 입력하면 하단이 --끼워넣기--라고 변하게 된다. (혹은 영어로 나올 수도 있다.) 이제 아래의 내용을 복붙해준다.
version: "3.9"
services:
  flask:
    image: wjdeorms27/docker-practice:1.0.0
    ports:
      - "80:5000"
  mongo:
    image: mongo:latest
    volumes:
      - mongo:/data/db/
    ports:
      - "27017:27017"

volumes:
  mongo:

  • 내용 다 적은다음에 끌 때는 어떻게 한다고?
    • esc키를 누르고 :를 입력한 다음, wq를 입력해주면 된다.
  • 처음 했을 때 아래의 에러가 났었다. 이유는 들여쓰기가 잘 되어 있지 않은 부분이 존재해서 였다.
  • 그 부분을 수정하고 나서는 이미지를 잘 받아와 아래와 같이 잘 생성된 것을 볼 수 있다.
  • 그리고 IPv4 주소를 브라우저에 입력하면 내가 띄운 이미지가 잘 돌아가야 한다. 하지만 나는 되지 않는다. ㅋ

CI/CD

Continuous Integration

  • 여러 개발자들이 함께 개발을 하는 과정에서 코드가 잘 작동하는지를 확인하는 것
  • CI를 하면 애플리케이션에 대한 새로운 코드 변경사항이 정기적으로 빌드 및 테스트되어 공유 리포지토리에 통합된다.
  • CI가 필요한 이유
    • 여러 명의 개발자가 같이 일하기 위해서
    • 지속적인 통합이 되지 않고 만약 특정한 날에 여러사람이 코드를 병합한다고 할 때, 서로의 작업영역이 충돌이 날 가능성이 존재함
    • 문제가 있는 경우를 수정하는게 더욱 복잡해지는 경우가 존재함
  • CI 방법
    • 테스트 코드 작성
    • 자동화된 테스트 실행
  • docker에서의 CI
    • docker를 사용하는 이유는 배포를 편리하기 하기 위해서이다.
    • 배포를 하기 전에 이 배포를 해도 괜찮은 상태인지 확인하기 위해서 CI를 사용한다.

Continuous Deployment

  • 반영된 소스코드가 실제 서비스에도 자동으로 반영이 되게 하는 것
  • docker를 사용하면 Continuous Deployment 과정이 더 쉽고 빠르게 진행된다.

GitHub Action을 사용해 CI 파이프라인 구축

테스트 코드의 중요성

$ pip install pytest

pytest로 테스트해보기

  • 기존의 파일 구조에서 app.py를 조금 수정해주고, 테스트 파일을 만들도록 하겠다.
  • 그리고 터미널에서 pytest만 쳐주면 테스트가 진행된다.
  • 그리고 모듈을 편하게 사용할 수 있도록 requirements.dev.txt 파일을 만들어주도록 하겠다.
-r requirements.txt
pytest==7.1.2
  • 위에서 작성한 코드들을 깃헙으로 올려주도록 하겠다.

GitHub Action 기본 문법

  • 6 가지 기본 용어
  1. Workflows: 자동화 하려고 하는 과정들
    • 한개 또는 여러 개의 job으로 구성되며, event에 의해서 시작된다.
    • 빌드, 테스트, 릴리즈, 배포 등의 작업이라고 생각하면 된다.
  2. Events : workflow를 trigger되는 행동들
    • push, pull request, cronjob 등이 있다.
  3. Jobs: 동일한 runner에서 실행하려고하는 여러 개의 step의 모임
  4. Steps: job을 구성하는 한개의 커맨드로 action이거나 shell command로 구성된다.
  5. Actions: 다른 곳에서 정의된 커맨드의 모음
  6. Runner: Job이 실행되는 환경
  • 실제 life cycle

yaml파일로 github action 정의

  • 아래의 코드 구조를 가져야 하며, yaml 파일을 생성해보도록 하겠다.
  • yaml 파일은 아래의 것을 사용하였다.
    • on : 어떤 events를 가지고 workflow를 실행할 것인가?
      • 우리는 push를 사용하며, main 브랜치에 푸시가 오면 실행하고 싶어 아래와 같이 설정함
    • jobs
      • python으로 hello world를 출력하는 프로그램을 짠다.
      • runs-on : 어떤 runner에서 프로그램을 돌릴 것인지 결정
      • steps : job은 여러 개의 step으로 구성되어 있다.
        • uses : 다른 사람이 정의해 놓은 것을 사용할 수 있다.
          • checkout : 깃헙의 특정 위치로 가달라는 요청을 수행해줌
          • setup-python : python 3.8 버전을 깔아달라는 요청 수행
        • run : shell command를 사용할 수 있다.
name: learn-github-action
on:
  push:
    branches:
      - main
jobs:
  python-hello-world:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-python@v2
        with:
          python-version: "3.8"
      - run: python -c "print('hello world')"
  • 이제 위의 yaml 파일을 github에 올리도록 하자.
  • 파일을 올린 뒤, action 탭으로 가면 yaml 파일이 실행 완료되어 있고, 그 내용은 아래와 같다.
  • 한 번 더 눌러서 안으로 타고 들어가면 아래와 같은 결과가 나오고, hello world를 클릭해보면 출력되는 것을 볼 수 있다.

github action을 통해 CI pipeline 생성하기

  • github action은 .github/workflows/ 하위에 yaml 파일을 만든다.
name: ci-pipeline
on:
  push:
    branches:
      - main
jobs:
  run-test-code:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-python@v2
        with:
          python-version: "3.8"
      - run: pip install -r requirements.dev.txt
      - run: pytest
  • 아래의 파일구조를 가지게 된다.
    • 앞에서 테스트한 파일은 삭제해주어 트리거가 다시 되지 않도록 해주었다.
  • 위의 파일을 깃헙에 올린 뒤, action 탭으로 가 테스트 결과를 확인해보자.
  • 이제 깃헙에 코드를 올릴 때마다 자동으로 action에서 테스트를 진행하게 될 것이다.
  • 코드가 잘못 되어 있다면 에러가 나는데, 이에 대한 것도 실습해보도록 하겠다.
  • test_utils.py의 내용을 일부러 틀리게 적어보았다.
from utils import get_movie_info


def test_get_movie_info():
    test_url = "https://movie.naver.com/movie/bi/mi/basic.nhn?code=185293"
    title, image, desc = get_movie_info(test_url)

    assert title == "내일의 기억ㅇㄹㅇㄹㅇㄹ"
    assert image == "https://movie-phinf.pstatic.net/20210406_131/1617688160755B157W_JPEG/movie_image.jpg?type=m665_443_2"
    assert desc == """사고로 기억을 잃은 채 깨어 난 수진 옆엔자상한 남편 지훈이 그녀를 세심하게 돌봐주고 있다.그리고 집..."""
  • 틀린 내용에 대한 에러가 났고, 이를 정확히 짚어주었다.

메인 브랜치에 push할 때 docker image 생성 및 push

  • docker access token을 먼저 발급받아야 한다. 링크를 타고 가서 받으면 된다.
    • 박스 처리된 부분에 있는 시크릿키를 복사해서 가지고 있어야 한다.

  • 토큰을 발급받은 후, 깃헙으로 돌아가 아래의 작업을 진행한다.


  • 동일한 방식으로 나의 dockerhub 아이디를 넣어주면 된다.
  • 이제 ci-pipeline.yaml 파일을 수정해주도록 하겠다.
name: ci-pipeline
on:
  push:
    branches:
      - main
jobs:
  run-test-code:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-python@v2
        with:
          python-version: "3.8"
      - run: pip install -r requirements.dev.txt
      - run: pytest
  build-image:
    needs: [run-test-code]
    runs-on: ubuntu-latest
    steps:
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v1
      -
        name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1
      -
        name: Login to DockerHub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      -
        name: Build and push
        id: docker_build
        uses: docker/build-push-action@v2
        with:
          push: true
          tags: ${{ secrets.DOCKERHUB_USERNAME }}/docker-memo:latest
      -
        name: Image digest
        run: echo ${{ steps.docker_build.outputs.digest }}
  • 우리가 앞에서 setting에 등록한 토큰과 아이디를 ${{ }}를 통해 불러와 사용하게 된다.
  • github에 push를 한 뒤, action 탭에 가서 확인해보면 아래와 같은 화면이 나오게 된다. test를 한 뒤, image가 빌드되도록 연결이 되어 있는데, 이것은 yaml 파일에서 우리가 쓴 with를 통해 연결된 것이다.
  • dockerhub에 가 우리가 만든 이미지가 잘 생성되었는지 확인해보도록 하겠다.
  • 이런 의문이 들 수 있다. 이게 진짜 내가 만든 이미지라고? 어떻게 확인하는데?
    • 먼저 github action에서 build-image를 클릭해보면 아래의 정보를 확인할 수 있다. 이 값을 외우고 dockerhub에 가서 비교해보자.
    • dockerhub의 이미지를 클릭해 들어가보면 빨간 박스 안에 있는 내용이 있다. 이 부분이 위의 빨간 박스와 같다는 것을 알 수 있고, 우리가 test를 진행하면서 이미지가 생성되도록 한 부분이 제대로 실행된 것을 알 수 있다.

GitHub Action을 사용해 CD 파이프라인 구축

  • Continuous deployment의 과정
    • 서버에 접속 + docker compose up
    • docker이기 때문에 위의 작업만 하면 끝!
  • CD를 위해 먼저 docker-compose.yaml을 서버에 올려주도록 하자.
    • ssh key와 서버 주소가 필요하다.
    • github secrets에 secret 두개를 추가
      1. PRIVATE_KEY: 서버접속에 필요한 ssh key
      2. HOST: 서버 private ip (aws의 IPv4 주소)
  • Dockerfile 수정
FROM python:3.8-slim AS builder

ADD requirements.txt requirements.txt

RUN pip install -r requirements.txt

FROM python:3.8-slim-buster
COPY --from=builder /usr/local/lib/python3.8/site-packages/ /usr/local/lib/python3.8/site-packages/

ADD templates templates

ADD app.py .

ADD utils.py .

CMD ["python", "app.py"]
  • docker-compose.yaml
    • 아래와 같은 빨간 박스가 남아있다면 꼭 지워줘야 한다. (volumes 또는 templates)
version: "3.9"
services:
  flask:
    image: wjdeorms27/docker-memo:latest
    ports:
      - "80:5000"
  mongo:
    image: mongo:latest
    volumes:
      - mongo:/data/db/
    ports:
      - "27017:27017"

volumes:
  mongo:
  • ci-cd-pipeline.yaml
name: ci-cd-pipeline
on:
  push:
    branches:
      - main
jobs:
  run-test-code:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-python@v2
        with:
          python-version: "3.8"
      - run: pip install -r requirements.dev.txt
      - run: pytest
  build-image:
    needs: run-test-code
    runs-on: ubuntu-latest
    steps:
      -
        name: Set up QEMU
        uses: docker/setup-qemu-action@v1
      -
        name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1
      -
        name: Login to DockerHub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      -
        name: Build and push
        id: docker_build
        uses: docker/build-push-action@v2
        with:
          push: true
          tags: ${{ secrets.DOCKERHUB_USERNAME }}/docker-memo:latest
      -
        name: Image digest
        run: echo ${{ steps.docker_build.outputs.digest }}
  cd-pipeline:
    needs: build-image
    name: continuos deploy
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@master
      - name: copy file via ssh password
        uses: appleboy/scp-action@master
        with:
          host: ${{ secrets.HOST }}
          username: ec2-user
          key: ${{ secrets.PRIVATE_KEY }}
          port: 22
          source: "docker-compose.yaml"
          target: "/home/ec2-user/"
      - name: executing remote ssh commands using password
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.HOST }}
          username: ec2-user
          key: ${{ secrets.PRIVATE_KEY }}
          port: 22
          script: "docker-compose pull && docker-compose up -d"
profile
https://github.com/nikevapormax

0개의 댓글