ASAC-SK플래닛 T아카데미 데이터 엔지니어

25.11.20 31일차 [Docker-compose ubuntu EC2 환경에서 구동 확인, Docker 기반 CI/CD 실습]

Datadesigner 2025. 11. 20. 12:40

오늘 오전에는 Docker-compose를 ec2 환경에서 구동 확인과

Docker 기반 CI/CD 수행하기 위한 세팅을 하고있다.

 

 


Docker-compose
  • 워크플로우
    • AWS EC2 세팅
      • EC2에 Docker, Docker compose가 사전에 설치되어있어야함
      • 필요 시 인스턴스 유형을 상위 레벨로 업그레이드 필요함
    • 기본 프리티어 상 t3.micro에 메모리가 부족해서 ec2환경에서 구동이 안됐다.
    • 그래서 로컬 메모리를 공유해서 쓰는 명령어를 수행했다.
  • 메모리 확인 / 현재 ec2 구동 후 mobaXterm으로 세션에 들어간 상태이다.
# 최신 버전으로 패키지 업데이트
sudo apt-get update

# 메모리 체크
free -h
---
               total        used        free      shared  buff/cache   available
Mem:           914Mi       366Mi       198Mi       2.7Mi       514Mi       547Mi
Swap:             0B          0B          0B
# 최소 2기가 이상 운용 필요함
# 상위 인스턴스 (t3.small 급 이상 교체) OR SWAP 메모리 통해서 확장
# 하드디스크 공간를 메모리로 잡아서 활용 (스왑메모리)

# nano 접속
nano memory.shell
# 1. 2GB 크기의 swapfile 생성
sudo dd if=/dev/zero of=/swapfile bs=128M count=16

# 2. 권한 설정 (읽기/쓰기만 가능하도록)
sudo chmod 600 /swapfile

# 3. Swap 영역으로 설정
sudo mkswap /swapfile

# 4. Swap 활성화
sudo swapon /swapfile

# 5. 재부팅 후에도 유지되도록 fstab 등록
echo '/swapfile swap swap defaults 0 0' | sudo tee -a /etc/fstab
# 파일 편집
nano memory.sh
# 위의 내용을 기재하여 저장
# 실행
sh memory.sh
# 메모리 확인
free -h
---
               total        used        free      shared  buff/cache   available
Mem:           914Mi       380Mi       435Mi       2.7Mi       255Mi       533Mi
Swap:          2.0Gi          0B       2.0Gi
# 도커 설치
sudo apt-get install -y docker.io

# 도커 권한 부여 -> ubuntu 로그아웃 -> 로그인
sudo usermod -aG docker ubuntu

sudo reboot

# docker compose 설치
sudo apt-get install -y docker-compose
sudo apt-get install -y docker-compose-plugin

 

이후 docker-compose를 적용한 dev폴더를 통째로 업로드한다, GUI가 아니라면 조금 힘들듯?

  • docker-compose가 적용된 dev 폴더를 통째로 ec2 서버에 업로드
    • MombaXterm or ftp 사용 하던 관계 없음
    • dev 업로드 (사용툴 별로 상이함)

UBUNTU 환경 안 DEV 폴더

 

이후 Docker-compose up -b --build 명령어를 사용하면

ubuntu상에서 docker-compose가 구동되어서 인스턴스 시작한 퍼블릭IP주소로 들어가면 로컬에서 하던것과 같이 작동하는것을 확인할 수 있다. 웹사이트를 만들고 nginx를 통해서 ip를 프록시하고 fastapi를 통해서 웹을 띄우고 데이터베이스와 연결되고 mysql 컨테이너 또한 작동하는것이다.

 

이제 git action을 이용해서 push하는순간 이 서비스가 구동되게 연동해야 한다, 그리고 그것이 ci/cd이다.

 


Docker CI/CD
  • 로컬 프로젝트 구성
    • dockerfile 브런치를 기반으로 dockercompose 브런치 구성
    • 불필요한 파일 삭제 > docker-compose.yml 파일 주석 제거
    • 목표
      • 기능 조정, 옵션 조정, gitaction에 맞춰서 수정 및 파일 생성
      • dockercompose 브런치에 push를 수행하면 자동으로 cicd 처리
      • docker hub를 이용하여 커스텀 이미지를 배포받아서 서버측에 세팅
  • docker-compose.yml 파일 수정
services:
  db:
    image: mysql
    container_name: mysql_db
    # unless-stopped : 오류로 중단시, 서버 재부팅시 -> 자동실행, 수동정지후->재가동x
    # always : 오류로 중단시, 서버 재부팅시, 수동정지후 -> 자동실행
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} # .env로 대체 가능함 -> 시크릿 변수등 체크
      MYSQL_DATABASE: memo
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
    volumes:
      - mysql_vol:/var/lib/mysql
    ports:
      - "3306:3306"
    networks:
      - my-net
  
  app:
    # 도커 허브(일종의 레퍼지토리)를 기반으로 이미지 사용
    # 도커허브상계정명(프로필명)/이미지명:태그명
    # 시크릿 변수에서 사용한다는 전제
    image: ${DOCKER_USERNAME}/fastapi-app:latest
    container_name: fastapi_app
    restart: always    
    command: uvicorn main:app --host 0.0.0.0 --port 8000
    # 볼륨 마운트 제거
    #volumes:
    #  - ./app:/app    
    environment:
      DATABASE_URL: "mysql+pymysql://guest:1234@db:3306/memo"
    networks:
      - my-net
    depends_on:
      - db

  nginx:
    # 도커허브내 커스텀 이미지 활용
    image: ${DOCKER_USERNAME}/nginx-proxy:latest #nginx:alpine
    container_name: nginx_proxy
    restart: always
    ports:
      - "80:80"
    #volumes:
    #  - ./nginx/web.conf:/etc/nginx/conf.d/default.conf
    networks:
      - my-net
    depends_on:
      - app
    
networks:
  my-net:
    driver: bridge

volumes:
  mysql_vol:

 바뀐 점

UNLESS-STOPPED -> ALWAYS  주석에 설명 있음

BUILD 수정

볼륨 마운트 삭제

시크릿 변수 추가

 

이후 nginx 용 Dockerfile 추가

이미지 구성과 필요한 파일 카피 명령어 추가

 

그 다음 env파일을 통해서 gitaction에 저장할 시크릿 변수를 등록했다.

  • git action에 저장할 시크릿 변수 등록
    • 도커 허브 계정 (프로필명, 엑세스 토큰)

토큰 발급

  • github 상 시크릿 변수
    • 시크릿 변수 목록
# 시크릿변수
- MYSQL_ROOT_PASSWORD
- MYSQL_USER
- MYSQL_PASSWORD
- DOCKER_USERNAME
- DOCKER_PASSWORD
- EC2_HOST
- EC2_USERNAME
- EC2_KEY

필요한 시크릿변수 목록이다,

  • Setting > secrets and variables > Actions
  • new repository secret 클릭하여 추가 혹은 수정(기존에 존재하면)

이렇게 시크릿변수들을 git setting 상에서 추가해준다.

이제 gitaction을 위한 파일들을 설정해준다.

  • gitaction 파일 설정
    • 위치

위치는 dev폴더가 있는곳과 같은 레벨로 해주면 된다.

deploy.yml 파일로 git action이 작동할 수 있도록 세팅해준다.

name: Docker 기반 CICD

# dockercompose 브런치가 push 되면 트리거 발동되어서 jobs가 수행됨
on:
    push:
        branches: [ "dockercompose" ]

jobs:    
    # git build push 작업
    docker-build-deploy:        
        runs-on: ubuntu-latest
        steps:        
            - name: Code Checkout
              uses: actions/checkout@v3

            - name: 검증
              run: |
                pwd
                ls ./dev -al
              shell: bash
            
            # 도커 허브 로그인 단계 v2/v3
            - name: Login to Docker Hub
              uses: docker/login-action@v2
              with:
                username: ${{ secrets.DOCKER_USERNAME }}
                password: ${{ secrets.DOCKER_PASSWORD }}
            
            # fastapi 관련 앱이 설정되어 있는 이미지 생성 및 도커허브 푸시 v4~v6
            - name: Build and Push fastapi 앱
              uses: docker/build-push-action@v4
              with:
                # Dockerfile 위치
                context: ./dev/app
                file: ./dev/app/Dockerfile
                push: true
                tags: ${{ secrets.DOCKER_USERNAME }}/fastapi-app:latest

            # 커스텀된 nginx 이미지 생성 및 도커허브 푸시 v4~v6
            - name: Build and Push nginx
              uses: docker/build-push-action@v4
              with:                
                context: ./dev/nginx
                file: ./dev/nginx/Dockerfile
                push: true
                tags: ${{ secrets.DOCKER_USERNAME }}/nginx-proxy:latest
    
    # 2. EC에 배포
    EC2-deploy:
        # 반드시 사전에 fastapi, nginx 이미지가 도커허브에 등록되어 있어야한다
        needs:  docker-build-deploy
        runs-on: ubuntu-latest
        steps:
            # 새로운 잡에서 새롭게 리눅스 할당 소스코드를 체크아웃함
            - name: Code Checkout
              uses: actions/checkout@v3
          
            # 아래 파일은 소스코드를 체크아웃함으로써 획득할 수 있다.
            # AWS의 EC2에 docker-compose.yml 파일을 업로드
            # appleboy/scp-action@master => EC2에 파일 카피 기능 제공 도구
            - name: Copy docker-compose.yml to EC2
              uses: appleboy/scp-action@master
              with:
                host: ${{ secrets.EC2_HOST }}
                username: ${{ secrets.EC2_USERNAME }}
                key: ${{ secrets.EC2_KEY }}
                port: 22                
                source: "./dev/docker-compose.yml"
                # /home/ubuntu/deploy/dev/docker-compose.yml 생성됨
                target: "/home/${{ secrets.EC2_USERNAME }}/deploy"

            - name: Docker-Compose Up to EC2 via ssh
              uses: appleboy/ssh-action@master
              with:
                host: ${{ secrets.EC2_HOST }}
                username: ${{ secrets.EC2_USERNAME }}
                key: ${{ secrets.EC2_KEY }}
                port: 22
                script: |
                  # 작업 디렉토리 이동( docker-compose.yml 위치로 이동)                  
                  cd /home/${{ secrets.EC2_USERNAME }}/deploy/dev

                  # 환경변수 생성
                  echo "DOCKER_USERNAME=${{ secrets.DOCKER_USERNAME }}" > .env
                  echo "MYSQL_ROOT_PASSWORD=${{ secrets.MYSQL_ROOT_PASSWORD }}" >> .env
                  echo "MYSQL_USER=${{ secrets.MYSQL_USER }}" >> .env
                  echo "MYSQL_PASSWORD=${{ secrets.MYSQL_PASSWORD }}" >> .env

                  # 최신 이미지 가져오기 -> 
                  # 최초 cicd 할때는 이미지를 모두 다운로드
                  # 이후 cicd 할때는 변경된 이미지(최신)만 다운로드
                  docker-compose pull

                  # 컨테이너 구성
                  docker-compose up -d

                  # docker-compose.yml 구성이 변경되어서 
                  # 이미지가 미사용되는것이 있을수 있음 -> 공간확보
                  docker image prune -f

 

deploy.yml  세팅 단계

1. 브런치 세팅
workflow명 : docker 기반 cicd

2. test1 ->  checkout jobs 세팅

이 코드들이 깃액션으로 올라가서 순서대로 작업을 수행한다.
ubuntu를 불러오고, action/checkout@v3 를 가져와서 파일들을 모두 가져온다, 이후 검증작업

fastapi-cicd 루트 폴더 내의 파일들을 모두 가져왔따.


3. test2 -> dockerhub 로그인 위한 git action 도구 추가

docker/login-action@v2 를 가져와서 사용한다, 이 도구가 도커허브로 로그인을 도와준다, 시크릿변수는 깃에서 설정한 변수

4. test3 -> build and push 추가, 도커 허브에 fastapi 앱 이미지, nginx 이미지 빌드 및 푸쉬

작업의 이름을 설정해주고 build-and-push-action@v4 도구를 가져온다.
그리고 이미지를 생성하는 dockerfile이 있는 경로를 지정해준다.

태그는 도커 상에서의 내 아이디이고 이미지명은 AWS에서 돌아갈 이미지와 똑같이 맞춰준다 = docker-compose상 이름
깃에 커밋해주고 깃액션이 작동하면
이렇게 도커허브상에서 가상이미지가 만들어진걸 확인할 수 있다.

 

5. test4 -> EC2 deploy 기능 추가, yml파일 EC2에 업로드 기능 appleboy 기능 사용하여 추가
먼저 반드시 사전에 fastapi, nginx 이미지가 도커허브상에 저장되어있어야 한다.
그래서 depends_on 과 비슷한 needs 명령어로 이전 작업을 지정해준다.

그리고 aws에서 작업을 돌려줄 docker-compose.yml 파일을 복사하는 도구를 사용해준다.
이 때 aws에 자동으로 로그인하기 위해서 시크릿변수를 사용해준다.
현재 로컬파일의 경로를 지정해주고, aws상에서 새롭게 파일을 복사해 올 주소 또한 지정해준다.
needs 명령어로 인해서 docker-build-deploy가 끝난 후 EC2-deploy가 돌아가는 모습이다.

6. test5 ->  yml파일 EC2에서 컨테이너 구성 명령 추가, 최종 .yml 파일 구성

마찬가지로 appleboy 도구를 사용해서 EC2에 붙어준 후, ununtu 내에서 수행할 명령어들을 미리 입력해준다.
이 때 docker-compose가 작동하기 위한 시크릿 변수를 제공해줘야 하기 때문에.env파일에 시크릿 변수를 넣어준다.
그리고 컨테이너 구성 명령어까지 입력해준다.

이제 깃액션만 수행해도
\

AWS로 할당받은 IP 주소 사이트에서 main.py의 내용이 정상적으로 작동하는 모습을 볼 수 있다.
사이트 ip는 가렸다.

aws상에서도 gitaction으로 생성한 이미지가 정상적으로 작동하는 모습이다.

 

Docker 기반 CI/CD 현재 작업 흐름도
# Docker 기반 CI/CD 흐름도
로컬 PC 개발 -> GIT 특정브런치 PUSH -> 이벤트 감지 -> Git Action 작동
-> xxx.yml에 상세하게 잡들 기술 -> 커스텀으로 구성
-> 소스코드를 체크아웃 (git action에서 제공하는 리눅스에 소스코드 체크아웃)
-> 검증
-> 도커 허브 로그인 -> git action에서 제공하는 리눅스에 세션이 생성됨(사용자명,엑세스토큰 제공(시크릿변수))
-> fastapi 앱, 커스텀된 nginx 이미지를 Docketfile 생성하여(build) -> 푸시(본인 계정의 도커허브 레퍼지토리상에)
-> 이후 git action 명령을 통해 EC2에 접속 -> EC2상에서 docker-compose 수행, 작동

 

DOCKER CICD 끝~~


CICD 이녀석,,,재밌다

 

문법이랑 각종 아무것도 모르겠는거 할때보다 훨씬 재밌고 다른것보다 아주아주아주약간 더 이해가 되는 느낌이었다.

 

이 쪽이 나랑 잘 맞는걸까 아니면 시키는대로만 하면 문제가 안생겨서 그런걸까

 

나는 뭐가 잘 맞는걸까 생각을 해봐야될거같은데

 

그래도 점점 더 예전에 배웠던 단편적인 기술들이 왜 배웠고, 왜 그렇게 사용했고에 대한 이해가 조금씩 퍼즐이 맞춰지는것 처럼 돌아갈 때가 있다.

 

아 그래서 이렇게 했구나~ 근데 저번에 말한거같은데 이거

 

예전부터 이런건 썩 좋아했던것같다.

 

대학교때도 '그나마' 내가 컴퓨터쪽은 조금 잘 알고있는 애였는데

그래서 프로그램 설치라던가 프로그램 기능 사용 등등은 다 나한테 물어봤었다 자랑 아닌 자랑 히히

 

그래서 컴퓨터 프로그램 소모임 회장도 했었는데 과거의 영광일뿐

 

그런데 지금 경로를 지정하고 이름을 지정하고 변수로 빼고 이 변수가 어디에서 세팅되어서 여기서 작동하고

그것을 위해서 어떤 밑작업을 하고 이러한 작업들이 썩 재미있었던 것 같다.

 

나는 명령어 칠 때가 제일 재밌다 그냥 아무생각없이 턱턱 들어가면 되니까

타자도 느린 편은 아니라서 우다다다 칠때 약간 세간에서 생각하는 개발자가 된 것 같은 기분이 조금 든 달까?

하하 까불지 말지어다

 

이제 CICD파트는 마무리 되는것같고 다음부터는 데이터 분석과 쿠버네티스를 들어가야 한다.

근데벌써 11월 말이야...벌써 두달이 지났다고?

 

학원 다니기 시작하고 이것저것 다양한 도전의 꿈이 있었는데 이제 진짜 미룰 때가 아닌 것 같다,

 

시간 날 때라는 말은 이제 없다, 시간 내서 해야된다

 

열심히 하자