Github에서 제공하는 개발의 workflow를 자동화할 수 있게 도와주는 CI/CD 툴
CI/CD
CI (Continuous Integration): 테스트, 빌드 등의 프로세스를 지속적으로 실시해 프로덕션 환경의 품질을 유지하는 것을 의미한다.
CD (Continuos Delivery or Continuous Deploy): 프로덕션 서비스를 실제 사용자들에게 배포하는 프로세스를 의미한다.
WorkFlows
하나 이상의 작업(job)을 실행하는 자동화 프로세스
Workflow는 GitHub repository에 체크인 된 YAML 파일에 의해 정의됨.
NGINX
웹 서비스는 클라이언트->웹서버->WAS->DB 순으로 요청, 반대로 응답한다.
웹 서버는 클라이언트의 요청에 따라 정적 파일을 응답하여 제공하는 소프트웨어로, NGINX가 이에 포함된다.
Gunicorn
Gunicorn은 Python WSGI로 웹서버 NGINX로부터 서버사이드 요청을 받으면 서버애플리케이션 Django로 전달하는 역할을 수행
WSGI는 파이썬 어플리케이션이 웹 서버와 통신하기 위한 인터페이스
(WAS는 웹서버와 외부프로그램을 연결하는 미들웨어이고, WSGI는 WAS가 파이썬 프로그램과 연결되는 경우에 웹서버와 WAS를 연결하는 미들웨어 역할)
보안, 비용 등의 문제로 정적인 요청은 NGINX에서 처리하고, 동적인 요청은 Gunicorn을 통해 처리
Dockerfile에서 nginx.conf파일을 불러옴
Docker
서버에 가상 컨테이너인 docker를 설치
AWS EC2에서 서버를 만들면 ubuntu OS로 인스턴스가 뜨지만 아무것도 없기에
Python, git이나 OS가 달라서 여러 문제가 생기기 때문에, 여러 OS에서 똑같은 환경을 만들어주기 위해 사용
개발 후 프로젝트 폴더 안에 아래 파일들이 새로 필요
(코드는 다른사람 코드를 많이 참고해 여기엔 굳이 안옮겨적겠다.. 다음에 내 깃허브 다시 보자)
.gitignore
.github
- workflows
- deploy.yml
Dockerfile
Dockerfile.prod
docker-compose.yml
docker-compose.prod.yml
.env
.env.prod
config
- docker
- entrypoint.prod.sh
- nginx
- Dockerfile
- nginx.conf
- scripts
- deploy.sh
settings.py를 settings디렉토리로 변경 후 분리(개발 환경과 프로덕션 환경의 데이터베이스 분리를 위해)
settings
- base.py
- dev.py
- prod.py
.gitignore
보안을 위해 깃허브에 올리지 않을 파일 목록을 작성한다.
https://www.toptal.com/developers/gitignore
deploy.yml
Github Actions가 배포를 위해 실행시키는 파일
develop브랜치에 push되었을 때 할 일들이 정의된다.
repository secret에 저장해둔 여러 변수와 scripts/deploy.sh 파일을 복사해간다.
branches: 진짜로 배포할 코드를 push하는 branch이름으로 변경
.env
외부에 노출되면 안되는 정보들을 작성한다.
(등호 뒤 띄어쓰기x)
dockerfile
Docker가 실행시키는 파일. 이미지를 만들기 위한 과정을 작성한다
Docker-compose.yml
여러 이미지들을 연결하고 관리하는 파일
이미지 : 내가 구축한 환경의 스냅샷
맥인 경우 아래와 같이 변경
db:
container_name: db
image: mysql:5.7 --> mariadb:latest
settings
기존 settings.py파일을 base.py로 바꾸고 DATABASES부분 삭제
dev.py와 prod.py파일에 각각 개발환경과 배포환경에서의 DATABASE 설정
Mysql연결
(코드 바꾸고 로컬에서 create database;)
데이터 베이스를 mysql로 바꾸고, 내 정보를 보호하기 위해 .env를 작성
.prod가 붙는 파일은 배포를 위한 파일
.env
DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1,[::1]
DJANGO_SECRET_KEY={django secret key}
DATABASE_NAME={데이터베이스 이름}
DATABASE_USER=root
DATABASE_PASSWORD={로컬 mysql root 비밀번호}
DATABASE_HOST=localhost
DATABASE_PORT=3306
장고 시크릿 키는 새로 발급 가능
https://miniwebtool.com/django-secret-key-generator/
(ci/cd의 과정에서 무슨 역할인지는 모르겠다)->ec2서버에서 도커 돌리기 전 에러 없는지 확인해보는 목적!
Docker Desktop 설치 https://docs.docker.com/desktop/mac/install/
docker-compose.yml 파일이 있는 폴더에서 진행
docker-compose -f docker-compose.yml up --build
브라우저에서 127.0.0.1:8000 접속 되는지 테스트
docker-compose -f docker-compose.prod.yml down -v 로 종료
-up : 파일에 정의된 모든 컨테이너 실행(띄우기)
--build : up할때마다 새로 build하기(코드 변경)
-d : background에서 계속 실행

LF will be replaced by CRLF in config/docker/config/docker/entrypoint.prod.sh. 오류난다면
git config --global core.autocrlf true 입력
+)
requirements.txt에 mysqlclient==2.2.0 PyMySQL==1.1.0
settings/base.py에 import pymysql pymysql.install_as_MySQLdb() 가 있어야
로컬에서 도커가 돌아간다. 이 코드들 설명은 여기
하지만 깃허브에 올리면 ci/cd 과정에서 오류가 난다.
인스턴스 시작 클릭인스턴스 시작

탄력적 ip
퍼블릭 IPv4 주소가 서버의 IP 주소
서버가 새로 뜨면 바뀔수도 있음 ip주소 고정하려면 탄력적 IP
EC2-> 탄력적 ip 주소 할당
(AWS 탄력적 IP는 무료지만, 할당받아놓고 연결 안해놓으면 월 500원씩 나간다. 삭제하려면 탄력적 IP를 릴리즈하면 된다.)
작업>탄력적ip주소 연결 하면 끝
파라미터 그룹: DB 옵션을 설정하기 위해 AWS 에서 제공하는 기능
1. 파라미터 그룹 생성
2. 편집 선택
3. time_zone을 Asia/Seoul로 변경
4. utf8mb4로 수정
character_set_client
character_set_connection
character_set_database
character_set_filesystem
character_set_results
character_set_server
5. utf8mb4_general_ci로 수정
collation_connection
collation_server
데이터베이스 생성데이터베이스 생성
배포를 위한 .env 파일을 만들자 방금 만든 EC2와 RDS를 연결하는 과정이다.
DATABASE_HOST={RDS db 주소: 엔드포인트}
DATABASE_DB=mysql
DATABASE_NAME={RDS 기본 database 이름:초기 데이터베이스 이름}
DATABASE_USER={RDS User 이름}
DATABASE_PASSWORD={RDS master 비밀번호}
DATABASE_PORT=3306
DEBUG=False
DJANGO_ALLOWED_HOSTS={EC2 서버 ip 주소:퍼블릭 DNS 주소},
DJANGO_SECRET_KEY={django secret key}
탄력적 ip를 설정했다면, ip 주소는 *
레포지토리의 settings -> Secrets and variables (Security) -> Actions -> New repository secret
ENV_VARS : .env.prod 전체 복붙
HOST : 퍼블릭 DNS 주소 (ec2-@@@@@.ap-northeast-2.compute.amazonaws.com)
KEY: EC2를 만들 때 생성한 ssh key(.pem 파일)
파일이 있는 위치로 이동한 뒤 cmd에서 mac : cat {파일 이름}.pem
----BEGIN RSA PRIVATE KEY---—부터 ----END RSA PRIVATE KEY---— 까지 (%는 포함x)
아무거나 커밋 후 Actions 탭에서 확인 가능
저장해둔 .pem파일이 있는 곳으로 가서
chmod 400 [파일명].pem
ssh -i "[파일명].pem" ubuntu@ec2-[내 ec2 ip].ap-northeast-2.compute.amazonaws.com
이 배포과정은 8월 초부터 계속 시도했었지만 못했던 것이다!! 드디어 하다니 눈물이난다 좔좔
1. Actions에서
RUN pip wheel --no-cache-dir --no-deps --wheel-dir /usr/src/app/wheels -r requirements.txt과정에서
ERROR: Command errored out with exit status 1: /usr/local/bin/python /usr/local/lib/python3.8/site-packages/pip/_vendor/pep517/_in_process.py get_requires_for_build_wheel /tmp/tmpy4lstatu Check the logs for full command output.
이유:
Dockerfile.prod에서 requirements.txt의 pip install mysqlclient에서 오류가 난건데, 애초에 이게 그냥 되는게 아니라서 그 윗줄에
RUN apk update && apk add python3 python3-dev mariadb-dev build-base && pip3 install mysqlclient && apk del python3-dev mariadb-dev build-base가 있다.
그래서 requirements.txt에서
mysqlclient==2.2.0 PyMySQL==1.1.0 주석처리하니까(지우니까) 빌드됐다.
2. 502 bad gateway nginx
빌드됐다고 초록 체크까지 뜨면서 모든 url에 502에러가 났다.
셸로 ec2에 연결하여
sudo docker ps -a로 실행중인 컨테이너를 보니 web이 없고 nginx만 돌아가고 있었다.
sudo docker logs web로 로그를 확인해보니
File "/home/app/web/bora/settings/base.py", line 20, in <module>
import pymysql
ModuleNotFoundError: No module named 'pymysql'
이는 내가 장고 버전이 4미만이라 db를 mysql로 바꾸니까 계속 Did-you-install-mysqlclient에러가 떠서 settings.py안에 썼던 코드인데, 딱 거기서 오류가 나서 도커가 안돌아가고 있었던 것이다.
오류를 잡으려고 많은걸 해봤는데 도커가 안돌아가고 있을거라고 생각은 못했고, 셸로 접근해서 docker 명령어들을 쓸 수 있는지 몰랐다.
문제되는 코드를 삭제하니 바로 잘 돌아갔다!!!!
문제를 해결하려고 적은 코드인데 그것때문에 이렇게 다른 쪽에서 문제가 일어나서 몇주를 삽질하다니..!
과정을 정리했지만
하나하나 원리나, nginx 도커 깃허브액션 guricorn등 그 과정을 완전히는 이해하지 못했고
엄청난 개념들이 더 많다는 것이 느껴진다.. 앞으로 차근차근 공부해나가자
일단 배포 해내서 기쁘긴 하다:) :0 얄루
곧 공부할 것:
http에 s 붙이기, unhealthy 문제, 이미지를 위한 S3
(앱은 상관없지만 웹에서는 프엔에 넘겨줄때 꼭 s를 붙여줘야만 한다고~..~)