[Docker] docker-compose를 이용한 프로젝트 배포
- -
✔️ EC2서버에서 일반적인 Django를 이용한 서버 배포 작업도 도움이 많이 되었다.
❗️ 요즘 추세로 DepOps에서 이용되는 MSA형태의 서버 배포 방식의 기본이 되는 Docker 배포 방식을 익히기 위해 docker-compose로 프로젝트를 배포해 보려고 한다.
🍃 EC2
1. 깃허브 repo 서버로 이동
➤ 프로젝트 폴더 생성
$ mkdir workspace
✔️ 프로젝트 작업물이 들어가 폴더를 생성한다.
➤ Git repo 받기
$ git clone -b <브랜치명> <HTTPS 주소>
✔️ 현재 main 레포지터리는 최신 상태가 아니기 때문에 develop 레포지터리를 clone 받도록 하자.
2. 서버에서 사용될 패키지 update 및 설치
➤ 사용 가능한 패키지 및 버전 정보 업데이트
$ sudo apt update
➤ Docker 설치
$ sudo apt install docker.io
✔️ 도커 버전은 docker --version
으로 확인
✔️ docker는 초기 설정에는 root계정만 사용할 수 있기 때문에 사용자 계정에 docker를 사용할 수 있는 권한을 부여해야 한다.
$ sudo usermod -aG docker ubuntu
➤ tree 설치하여 폴더구조 확인
✔️ docker로 프로젝트를 배포하기 위해서는 프로젝트 구조를 보고 작업할 부분이 있으니 미리 설치하여 tree를 사용할 수 있게 하겠다.
$ sudo apt-get install trr
$ tree ./ -d [depth]
3. 파일 설정
➤ django .secrets>secret.json
{
"DJANGO_SECRET_KEY": "[django 시크릿키]",
"AWS_ACCESS_KEY_ID": "[AWS 엑세스 키]",
"AWS_SECRET_ACCESS_KEY": "AWS 시크릿 엑세스 키",
"IMP_KEY": "Import 키",
"IMP_SECRET": "Import 시크릿 키"
}
✔️ 공개되지 않아야할 데이터를 .secret폴더의 json파일안에 보관해야한다.
✔️ 이 데이터는 로컬에는 가지고 있지만 github에는 올려놓지 않았기 때문에 따로 폴더, 파일을 만들어 소스를 넣어주자.
4. 프로젝트 실행할 가상공간 설치
➤ 가상공간 설치
가상공간$ sudo apt-get install virtualenv
설치된 apt 패키지 리스트 확인$ apt list --installed
기본이 되는 라이브러리 파일 생성$ sudo apt-get install build-essential
➤ 가상공간 생성
$ virtualenv env-devket --python=python3.10
➤ 가상공간 접속
$ source ./env-devket/bin/activate
➤ 로컬에서 사용하던 패키지 다운로드
$ pip install -r requirements.txt
➤ 파이썬, 장고 버전 확인
$ python3 -version
$ python3 -m djanog --version
➤ 사전 프로그램 설치
$ sudo apt-get update; sudo apt-get install make build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm \
libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev
5. 프로젝트 마이그레이션 파일 지우기
✔️ ❗️ 마이그레이션 파일을 지우는 이유는 현재 db.sqlite가 아는 postgresql로 변경 예정이기 때문에 사정에 마이그레이션을 하면 postgre로 연결할 때 충돌이 일어나는 것을 방지하기 위해
6. Dockerfile 생성
✔️ Docker가 읽어 실행이 될 Dockerfile을 생성하자.
FROM python:3.10.6-slim
WORKDIR /usr/src/app
COPY . .
RUN python -m pip install --upgrade pip
RUN pip install -r requirements.txt
WORKDIR ./Devket
CMD python manage.py runserver 0.0.0.0:8000
EXPOSE 8000
➤ 트리구조 확인
✔️ 아래와 같은 구조로 Devket(프로젝트), Dockerfile, requirement.txt를 동일한 depth로 일치시킨다.
✔️ 동일한 depth로 일치시킨 후 Django라는 최상위 폴더를 생서 후 그 안에 3개의 파일을 이동시켜준다.
참고 : tree 사용법
7. 프로젝트 이미지 빌드
$ docker build . -t devket
$ docker image ls
✔️ -t: 태그/devket 프로젝트를 이미지로 빌드
❓ 에러발생
invalid argument "Devket" for "-t, --tag" flag: invalid reference format: repository name must be lowercase
See 'docker build --help'
✔️ 위의 코드는 -t 태그로 입력되는 값은 모두 소문자여야한다는 문구이기 때문에 처음에 image를 Devket
으로 생성하려다 모두 소문자인 devket
으로 변경하여 다시 빌드를 진행
❓ 경고문 발생
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
✔️ 위의 문구는 pip를 사용자 계정으로 실행하면 권한이 손상되고 시스템 패키지 관리자와 동작이 충돌할 수 있다는 경고문이다. 특별히 pip를 루트로 실행하는 빌드 작업이 아니기 때문에 넘어가겠다.
➤ image 확인
$ docker image ls
✔️ 성공적으로 image가 생성한 목록을 확인하였다.
8. Dockerfile로 빌드 작업을 진행한 image 파일 container로 실행
docker run -d -p 80:8000 devket
✔️ 정상적으로 내가 docker로 띄운 프로젝트에 접속이 가능해 졌다.
9. docker 컨테이너로 nginx 배포하기
➤ nginx 배포 과정
➤ workspace에 nginx폴더 생성
$ cd workspace
$ mkdir nginx
➤ Dockerfile 생성
touch Dockerfile
FROM nginx
CMD ["nginx", "-g", "daemon off;"]
✔️ nginx를 foreground를 돌리기 위함
✔️ 컨테이너가 background로 실행되므로 nginx를 foreground로 돌리지 않으면 nginx가 exited됨
10. Dockerfile 이미지 빌드
docker build . -t devket-nginx
✔️ Dockerfile로 만든 devket 이미지와 devket-nginx 이미지를 실행시켜 보았다.
11. Docker Compose 설치
mkdir -p ~/.docker/cli-plugins/
curl -SL https://github.com/docker/compose/releases/download/v2.11.2/docker-compose-linux-x86_64 -o ~/.docker/cli-plugins/docker-compose
chmod +x ~/.docker/cli-plugins/docker-compose
docker compose version
$ sudo apt-get update
$ sudo apt-get install docker-compose-plugin
12. Docker Compose를 위한 폴더 구조 변경
✔️ 상위 폴더를 하나 생성 후 django 폴더를 생성해주었다.
✔️ 생성한 django폴더로 이동 후 django 폴더 안에 있는 nginx 폴더를 밖으로 옮겨서 django와 동일한 depth로 변경해 주었다.
13. requirements.txt
✔️ 일반 배포 과정에서 uwsgi를 사용하여 WAS를 작동하게 만들었지만 docker 배포과정에서는 gunicorn을 사용하여 배포를 진행하려고 한다.
gunicorn==20.1.0
14. Compose를 위한 django Dockerfile 수정
✔️ django안에 Dockerfile의 내용에 gunicorn을 추가
nginx가 연결되지 않아 화면이 나오지 않는 소스
FROM python:3.10.6-slim
WORKDIR /usr/src/app
COPY . .
RUN python -m pip install --upgrade pip
RUN pip install -r requirements.txt
WORKDIR ./Devket
CMD python manage.py runserver 0.0.0.0:8000
CMD gunicorn devket.wsgi:application --bind 0.0.0.0:8000
EXPOSE 8000
nginx가 연결된 소스
FROM python:3.10.6-slim
WORKDIR /usr/src/app
COPY . .
RUN python -m pip install --upgrade pip
RUN pip install -r requirements.txt
WORKDIR ./Devket
# RUN python manage.py collectstatic
CMD python manage.py runserver 0.0.0.0:8000
CMD gunicorn config.wsgi:application --bind 0.0.0.0:8000
EXPOSE 8000
✔️ devket이 config로 변경하여 작업을 진행하였는데
✔️ 그 이유는 gunicorn은 DB작업을 도와주는 WAS이기 때문에 프로젝트 명으로 된 devket이 아는 wsgi 파일이 들어있는 config로 설정을 해 주어야 한다.
15. Compose를 위한 nginx Dockerfile 수정
FROM nginx
RUN rm /etc/nginx/conf.d/default.conf
COPY default.conf /etc/nginx/conf.d/
CMD ["nginx", "-g", "daemon off;"]
# 컨테이너 안에 있는 default.conf를 지우고 서버에 있는 default.conf를 옮겨라
✔️ 컨테이너 안에 있는 default.conf를 지우고 서버에 있는 default.conf를 옮겨라
16. nginx>default.conf 생성
server{
listen 80;
server_name localhost;
location /{
proxy_pass http://devket-compose:8000;
}
}
17. docker-compose.yml 생성
version: "3"
services:
devket-compose:
build: ./Django
container_name: devket
restart: always
expose:
- "8000"
nginx-compose:
build: ./nginx
container_name: nginx
restart: always
ports:
- "80:80"
depends_on:
- "devket-compose"
✔️ docker-compose 실행 시, 읽어 실행시킬 설정 소스를 yml파일에 작성
❗️전체 폴더 구성
✔️ 명령어로 내가 만든 컴포즈를 image로 만들면서 없으면 build해라
$ docker compose up -d --build
➤ 이미지 생성 및 컨테이너 실행 성공
➤ 컴포즈 내리기
$ docker compose down
➤ 화면 불러오기 성공
✔️ 단, 불러오기는 성공했지만 js, css 파일은 불러오는데 실패하였다.
❗️ 주의사항
이 내용은 서버에서 일반 배포할때 보았던 문제이기 때문에 일반 서버 배포 시 작업 했던 내용을 도커 작업에 적용시켜 보자.
하지만 일반 배포할때 했던 내용을 진행해 보아도 제대로 나오지 않았다... 구글링 해서 보니 nginx가 static파일을 가지고 있지 않아서 라고 한다.
섹션 15 통합 yml 파일 작성에서 static 파일이 적용 안 되는 것 같습니다.
docker + nginx + django 에서 static file serve 해주기
static적용되지 않는 문제 해결
➤ 장고 설치
$ pip3 install django==3.2.13
➤ requirements.txt
$ pip3 install -r requirements.txt
➤ settings.py 코드수정
# STATIC
STATIC_URL = "static/"
STATICFILES_DIRS = [BASE_DIR / "static"]
✔️ static파일을 기본 경로에 public폴더로 생성되게 경로 설정 코드를 추가해 주었다.
➤ 모든 static파일 모으기
$ mkdir public
$ python3 manage.py collectstatic
✔️ 자동으로 public을 생성해 주지만 자동으로 생성하는 것은 ROOT권한으로 생성이 되기 때문에 아래와 같은 에러가 발생한다.
PermissionError: [Errno 13] Permission denied: '/home/ubuntu/workspace/devket-compose/Django/Devket/public/images'
➤ docker-compose.yml 파일 코드 추가
version: "3"
services:
devket-compose:
build: ./Django
container_name: devket
restart: always
expose:
- "8000"
nginx-compose:
build: ./nginx
container_name: nginx
volumes:
- ~/workspace/devket-compose/Django/Devket/public:/usr/src/app/Devket/static
restart: always
ports:
- "80:80"
depends_on:
- "devket-compose"
volumes:
static-volume:
✔️ 위의 volumes은 static파일을 저장시킬 저장소를 생성해 주는 역할이다.
✔️ ~/workspace/devket-compose/Django/Devket/public 경로에 있는 public파일을 nginx에 있는 /usr/src/app/Devket/static 에 static로 생성되게 코드를 추가해 주었다.
❗️ 현재 소스에서는 collectstatic로 모아진 public파일을 container로 실행시키면서 nginx로 이동시키고 있다. 하지만 이 작업을 하기 위해서는 server 즉 원본 소스에서 장고 설치이며 requirements.txt파일을 모두 다운로드 받고 python manage.py collectstatic 명령어를 실행 후 docker compose를 진행해야한다.
여기서 내가 원하는 방향은 docker compose를 진행하며 python manage.py collectstatic 명령문을 실행시키고 이 과정에서 생긴 프로젝트의 public 파일을 nginx로 옮기는 작업을 하고 싶은데 Dockerfile에 어떠한 명령어를 입력하여 이러한 작동을 하게 할 수 있는지 잘 모르겠다.
➤ nginx>default.conf 코드 수정
server{
listen 80;
server_name localhost;
location / {
proxy_pass http://devket-compose:8000;
}
location /static/ {
alias /usr/src/app/Devket/static/;
}
}
✔️ 위의 docker-compose.yml파일에 nginx경로로 옮겨준 static경로를 바라볼 수 있게 static경로 코드 수정
✔️ 만약 관리자 계정을 만들고 싶으면 컨테이너에 접속하여 생성시키자.
✔️ 현재 compose를 껐다가 키면 DB날아가는 모습을 확인 할 수 있다.
✔️ 이제 volume을 변경하여 서버에 유지시키는 작업과 s3에 저장하는 방법을 진행해보겠다.
🍃 AWS
static 파일을 S3를 바라보게 변경
1. 버킷 생성
➤ 버킷명 및 리전 선택
bucket 명 : dev-devket-bucket
➤ 객체 소유권
➤ 퍼블릭 액세스 차단 설청
2. S3사용 모듈 설치 코드 추가
➤ boto3 설치
$ pip3 install boto3
➤ django-storage 설치
$ pip3 install django-storages
➤ Django>Dockerfile
FROM python:3.10.6-slim
WORKDIR /usr/src/app
COPY . .
RUN python -m pip install --upgrade pip
RUN pip install -r requirements.txt
RUN pip install boto3
RUN pip install django-storages
WORKDIR ./Devket
# RUN yes | python manage.py collectstatic
CMD python manage.py runserver 0.0.0.0:8000
CMD gunicorn config.wsgi:application --bind 0.0.0.0:8000
EXPOSE 8000
✔️ docker image로 만들면서 boto3를 설치할 수 있게 명령어를 추가
✔️ 장고 프로젝트가 특정 storage를 사용할 수 있게 설치
➤ settings.py storages app 추가
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# custom apps
'rest_framework',
'pocket',
'storages',
]
3. IAM 설정
✔️ IAM을 설정하는 이유는 Amazon에서 제공하는 서비스간에 연결을 해주기 위해선 사용자를 추가한 후 그 사용자에 대한 접근 권한을 부여해 줘야 사용이 가능하기 때문에 설정이 필요한다.
➤ 사용자 추가- 권한(AmazonS3FullAccess)
✔️ 서버 일반배포에서 사용한 사용자를 그대로 사용
✔️ 권한 추가로 사용자를 등록 후 액세스 키ID와 비밀 액세스 키 담은 파일을 보관
➤ settings.py s3접속정보 설정
AWS_ACCESS_KEY_ID = get_secret('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = get_secret('AWS_SECRET_ACCESS_KEY')
AWS_REGION = 'ap-northeast-2'
AWS_STORAGE_BUCKET_NAME = 'dev-devket-bucket'
AWS_S3_CUSTOM_DOMAIN = f'{AWS_STORAGE_BUCKET_NAME}.s3.{AWS_REGION}.amazonaws.com'
AWS_DEFAULT_ACL = 'public-read'
DEFAULT_FILE_STORAGE = 'config.storages.S3DefaultStorage'
STATICFILES_STORAGE = 'config.storages.S3StaticStorage'
✔️ 위의 AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY의 변수 값은 .secrets>secret.json에 추가하여 보관하자.
➤ storages.py 스토리지 설정(config > storages.py)
from storages.backends.s3boto3 import S3Boto3Storage
class S3DefaultStorage(S3Boto3Storage):
location = "media"
class S3StaticStorage(S3Boto3Storage):
location = "static"
➤ nginx설정 변경(nginx>default.con)
server{
listen 80;
server_name localhost;
location / {
proxy_pass http://devket-compose:8000;
}
location /static/ {
#alias /usr/src/app/Devket/static/;
alias https://dev-devket-bucket.s3.ap-northeast-2.amazonaws.com/static/;
}
}
✔️ 기존에 바라보는 nginx의 /usr/src/app/Devket/static/를 바라보던 static경로를 aws의 s3을 바라볼 수 있게 설정 변경
❓문제점
✔️ 현재 nginx에 static 파일이 올라가지 않는 것 처럼 s3에도 docker-compose할때 올라가지 않는 문제가 발생하였다. s3에 대한 설정을 모두 하게 되면 올라갈거라 생각하고 docker-compose를 하게 되었는데 자동으로 올라가지 않아 container를 실행하여도 s3에 올가있는 정적파일을 바라보고 가져와야하는데 가져오지 못하고 있었다.
💡해결방안
✔️ docker-compose를 진행할때 s3에 static파일을 올리고 싶은데 그렇게 되지 못해서 서버안에서 s3에 관련된 pip install boto3, pip install django-storages 를 설치하고 python manage.py collectstatic 로 static파일을 모아주니 그제서야 s3에 static폴더가 생성되어 올라간 것을 확인 하였다.
🍃 S3의 postgresql(RDS) 바라보게 변경
1. 데이터 베이스 생성
➤ 엔진 옵션 & 템플릿
➤ 가용성 및 내구성
➤ 설정
➤ 인스턴스 & 스토리지
➤ 연결
➤ 데이터베이스 인증 & 모니터링
➤ 생성중
2. settings.py DB 설정 변경
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql_psycopg2",
“HOST": [RDS 엔드포인트],
"NAME": [DB 이름],# DB 명이 들어가야하는 줄 알았는데 postgres, 즉 마스터 사용자 이름이 들어간다.
"PORT": "5432",
"USER": [마스터 사용자 이름],
"PASSWORD": [비밀번호],
}
}
✔️ 엔드포인트 / 마스터 사용자 이름 / DB이름(postgres)
✔️ 기존 DATABASES 주석 처리
3. 서버 psycopg2 사용 설정
$ sudo apt-get install build-essential libpq-dev
$ pip install psycopg2-binary wheel
$ pip install psycopg2
FROM python:3.10.6-slim
WORKDIR /usr/src/app
COPY . .
RUN python -m pip install --upgrade pip
RUN pip install -r requirements.txt
RUN pip install boto3
RUN pip install django-storages
RUN apt-get update
RUN apt-get install -y sudo
RUN adduser --disabled-password --gecos "" hive \
&& echo 'hive:hive' | chpasswd \
&& adduser hive sudo \
&& echo 'hive ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers \
&& mkdir /var/run/sshd
RUN sudo apt-get install build-essential libpq-dev -y sudo
RUN pip install psycopg2-binary wheel
RUN pip install psycopg2
WORKDIR ./Devket
# RUN yes | python manage.py collectstatic
CMD python manage.py makemigrations
CMD python manage.py migrate
CMD python manage.py runserver 0.0.0.0:8000
CMD gunicorn config.wsgi:application --bind 0.0.0.0:8000
EXPOSE 8000
➤ Dockerfile에서 sudo 사용하기
➤ rds 연결할때 이슈사항
➤ 시스템의 필요없는 데이터 지우기
$ docker system prune --volumes
✔️ docker로 배포진행 시 테스트로 올렸다 내렸다를 반복하는데 불필요한 데이터가 생겨 용량을 비워줄 때 사용한다.
➤ createsuperuser의 경우는 필요한 경우에만 생성하기 때문에 Dockerfile에 명령어를 넣지 않고 직접 Container에 접속하여 계정을 생성해 주었다.
docker compose up -d
🍃기타 내용
ec2 용량 늘리기
ec2 용량 늘리기 2
No space left on device 오류 해결
'LANGUAGES > Django' 카테고리의 다른 글
[Django] django-crontab 스케줄러 작성 (0) | 2023.05.22 |
---|---|
[Django] 다양한 템플릿 태그 (0) | 2023.05.04 |
[Django] django-seed를 이용한 데이터 만들기 (0) | 2023.05.03 |
[Django] Django 커스텀 커맨드 만들기 (0) | 2023.05.02 |
[Django] debug_toolbar 사용하기 (0) | 2023.04.06 |
소중한 공감 감사합니다