새소식

LANGUAGES/Django

[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 사용법

 

Linux tree 명령어 사용법

 

www.lesstif.com

 

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 해주기

 

docker + nginx + django 에서 static file serve 해주기

기본적으로 장고는 정적파일 로드를 static 이라는 경로에 따로 모아놓고 진행을 한다. 따라서 실제 서비스 환경에서는 CSS나 이미지를 비롯한 정적 파일들을 해당 경로에 모아놔야 정상적으로 로

my-repo.tistory.com

 

 

섹션 15 통합 yml 파일 작성에서 static 파일이 적용 안 되는 것 같습니다. - 인프런 | 질문 & 답변

이제 거의 막바지인데 이런 오류가 나네요 ㅜㅜdocker-compose.yml 파일을 작성해서 stack을 만들었는데 사이트에 css가 적용 안되서 나옵니다.이전까지는 잘 나왔는데 뭐가 문제인 걸까요...[사진]제가

www.inflearn.com

 

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를 사용할 수 있게 설치

 

boto3를 사용하는 이유

 

AWS S3

python django code …

ehfgk78.github.io

django-storages를 설치하는 이유

 

[웹 프로그래밍 스쿨 10주차] 장고 3주차

이번 포스팅에서는 django를 배포하는 것에 초점을 두었다. 저번 주에 공부했던 pythonanywhere에 이어 이번에는 heroku 배포 방법과 aws에서 웹 사이트에 업로드하는 파일을 저장 하는 방법과 디비를 관

inoru.tistory.com

 

➤ 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 사용하기

 

docker container에서 sudo 사용하기

sudo 설치$ apt-get udpate && apt-get install -y sudo사용자 계정 추가$ adduser --disabled-password --gecos "" hive \ && echo 'hive:hive' | chpasswd \ && adduser hive sudo \ && echo 'hive ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers \ && mkdir /var/run/s

yongho1037.tistory.com

rds 연결할때 이슈사항

 

[Django] "database does not exist" when connecting to AWS RDS postgres DB

1. 문제 상황 Docker 위에서 Django를 사용해 AWS RDS에 DB를 연동시키는 과정에서 다음과 같은 에러가 발생하였습니다. "database does not exist" 분명히 AWS console에 접속하여 RDS가 존재하는 것을 확인하였으

someone-life.tistory.com

 

➤ 시스템의 필요없는 데이터 지우기

$ docker system prune --volumes

 

✔️ docker로 배포진행 시 테스트로 올렸다 내렸다를 반복하는데 불필요한 데이터가 생겨 용량을 비워줄 때 사용한다.

 

➤ createsuperuser의 경우는 필요한 경우에만 생성하기 때문에 Dockerfile에 명령어를 넣지 않고 직접 Container에 접속하여 계정을 생성해 주었다.

 

docker compose up -d

 

🍃기타 내용

ec2 용량 늘리기
ec2 용량 늘리기 2
No space left on device 오류 해결

 

Amazon EBS에서 ‘No space left on device’ 오류 해결

Amazon Elastic Block Store(Amazon EBS) 볼륨 크기를 늘리려고 했을 때 파일 시스템에 남은 공간 없음 오류가 표시됐습니다. 이 문제를 해결하려면 어떻게 해야 합니까?

repost.aws

 

AWS EC2 디스크 용량 늘리기

가끔 운영중인 EC2의 디스크가 부족해 디스크 용량을 늘려야 할 경우가 생긴다. 디스크 용량을 늘리는 방법은 생각보다 손쉬웠는데 EC2 를 stop 시키지 않아도 되었다. 그 방법을 정리해 보았다. AWS

leonkim.dev

 

ec2 용량 full일 때 대처법

용량 꽉참. ( df -h 로 확인.)루트볼륨 늘리기 (EBS 용량 늘리기)파티션 크기 늘리기 ( growpart 명령)파일시스템 크기 늘리기 (ext4일 경우 resize2fs 명령)끝보면 현재 용량이 꽉 차있다..EBS 콘솔에서 내

velog.io

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.