반응형

Django 프로젝트를 배포하는 방법은 서비스 규모나 환경에 따라서 여러가지가 있겠지만..

여기서는 단일 서버에 docker를 이용하여 서비스를 운영한다고 가정을 하고 배포하는 상황을 준비하였습니다.

 

 

서비스 구성

기본적으로 source code는 git을 통해서 관리가 되고 있고, 서버에 docker는 이미 설치되어 있다고 가정하겠습니다. 실제 상황에서는 CI/CD 툴을 이용해서 관리하겠지만, 여기서는 Django 프로젝트를 배포하는 것에만 포커스 하도록 하겠습니다.

 

대략적인 서비스 구성은 아래 그림과 같습니다.

 

실제 서비스라면 database도 준비가 되어야겠지만.. 여기서는 docker에서 nginx와 python만 container를 띄울 예정입니다. 여기서 storage는 static 파일들이 들어갈 위치인데요, Django의 경우 운영환경에서는 django app은 wsgi (혹은 asgi) 형태로 서비스를 제공하며, static 파일들은 웹서버가 직접 처리해 주는 형태로 서비스를 하기 때문에, storage를 별도로 지정해 두었습니다.

외부에서 해당 서버에 요청이 오면, 먼저 nginx가 요청을 받아서 처리를 하게 되는데, static 파일 등은 nginx 가 알아서 처리해주고, 그 외에 django app이 처리해야할 부분만 reverse proxy 형태로 전달해 주게 됩니다.

 

 

Django 서비스 배포 절차

Django 서비스를 배포할 때는 다음과 같은 과정들이 필요합니다.

1. python 가상환경 준비 (처음 한번만 필요)

2. 소스 코드 업데이트

3. 의존 모듈 설치

4. static 파일 collect

5. model migration

6. django app service launch

 

다음에는 각각의 작업을 command로 살펴보겠습니다.

 

 

 

Django 서비스 배포 - 디렉터리 설정

위에서 언급하진 않았지만, 여기서는 아래와 같이 디렉터리를 설정해 보았습니다.

 

기본적으로 /opt/docker 폴더에서 각각의 서비스 컨테이너에 대한 폴더를 생성합니다. (nginx, python)

각 서비스 컨테이너 별로 루트에 docker-compose.yaml 파일들을 위치시키게 됩니다.

nginx 에 대해서는 설정파일들은 conf 폴더에 넣을 예정이고, static 파일들은 static 폴더에 넣어 두면 됩니다.

python 도 역시 설정파일들을 conf 폴더에 넣고, 그 외에 필요한 script들은 scripts 폴더에 보관합니다.

그 외에 python 에는 app 폴더를 생성할 예정인데요, app 폴더는 git clone 후에 rename 해서 생성할 예정입니다. 

 

 

Django 서비스 배포 - 가상환경 준비

가상환경은 application 별로 독립된 python 환경을 구성하기 위해서 준비하는 과정인데, docker image를 빌드하는 경우에는 따로 독립된 환경을 사용하지 않아도 되지만, 여기서는 범용 python 이미지를 사용할 예정이기 때문에, local storage에 가상 환경을 생성해서 사용할 예정입니다. command는 다음과 같은데, 가상환경은 python docker container 안에서 실행할 예정입니다.

 

> python -m venv .venv

 

 

Django 서비스 배포 - 소스 코드 업데이트

소스코드 업데이트는 git pull (혹은 clone) 명령어로 처리가 가능합니다. 물론 먼저 서버에 git이 설치가 되어 있어야 합니다.

 

처음 소스를 받아올 때는 clone 명령어를 사용합니다.

 

> git clone <repository url>

 

 

추후에 업데이트 하는 경우에는 pull 명령어를 이용하면 됩니다.

 

> git pull

 

 

Django 서비스 배포 - 의존 모듈 설치

python에서 필요로 하는 모듈을 설치합니다. 로컬 개발환경에서는 간단히 pip 명령어로 처리가 되지만.. 여기서는 가상환경을 이용하기 때문에 아래와 같이 명령어를 입력합니다. 역시 python docker container 안에서 실행되어야 합니다.

 

> ./.venv/bin/python -m pip intstall -r requirements.txt

 

 

Django 서비스 배포 - static 파일 collect

소스 코드 repository 에 넣어둔 static 파일들을 모아주는 과정입니다.여기서는 가상환경을 이용하기 때문에 아래와 같이 명령어를 입력합니다. 역시 python docker container 안에서 실행되어야 합니다.

 

> ./.venv/bin/python manage.py collectstatic --no-input

 

 

Django 서비스 배포 - model migration

모델을 migration 합니다. 실제로는 database 테이블을 생성 또는 변경 하는 과정입니다. 역시 python docker container 안에서 실행되어야 합니다.

 

> ./.venv/bin/python manage.py migrate

 

 

Django 서비스 배포 - django app service launch

django app 서비스를 실행합니다. 앞에서 잠시 언급한데로 wsgi 혹은 asgi 를 이용할 예정이기 때문에, 로컬 개발환경에서와는 조금 다른 명령어를 사용합니다. 역시 python docker container 안에서 실행되어야 합니다. 그리고 host를 지정하지 않으면 127.0.0.1 로 지정이 되는데, 컨테이너 외부에서 접속을 하기 위해서는 0.0.0.0 으로 바인드를 해줘야 합니다. port는 nginx에서 매핑할 예정이기 때문에 크게 중요하지 않아서 default 포트인 8000으로 지정해 주었습니다. 

 

> ./.venv/bin/python -m uvicorn <asgi applcation> --host 0.0.0.0 --port 8000 --workers 4

 

 

참고로 uvicorn을 이용하기 위해서는 python module 을 미리 설치해 주어야 합니다. 만약 requirements.txt에 해당 모듈이 들어있지 않다면 별도로 설치를 해 줍니다. (2024년 2월 현재 0.27.1 버전이 최신이네요..)

 

> ./.venv/bin/python -m pip install uvicorn==0.27.1

 

 

실제 예시

이번에는 위에서 설명한 내용을 실제로 서버에 반영해 보겠습니다. 소스코드는 예전에 제가 생성해 두었던 기본 django tutorial 코드를 이용하도록 하겠습니다. https://github.com/shineum/django_tutorial.git

 

먼저 /opt/docker/python 폴더에서 소스 코드를 clone 합니다.

 

> git clone https://github.com/shineum/django_tutorial

 

 

그리고 django_tutorial 폴더를 app 으로 rename 합니다.

 

> mv django_tutorial app

 

 

django app에서 사용할 script 들을 https://github.com/shineum/django_scripts.git 에서 다운로드 합니다. 그리고 script 들을 scripts 폴더에 위치시킵니다.

 

docker 에서 가상 환경을 생성합니다. python 은 3.12.2-slim-bullseye 버전을 사용하였는데, 버전은 상황에 맞게 설정하면 됩니다.

 

> docker run -v ./app:/opt/app -v ./scripts/init.sh:/entrypoint.sh -it --rm python:3.12.2-slim-bullseye sh ./entrypoint.sh

 

 

소스 코드는 바로 clone 해서 준비가 되어 있으니 여기서는 업데이트가 필요 없지만, 코드가 변경된 경우에는 git pull 명령어를 이용해서 반영해 주면 됩니다. 

 

 

바로 의존 모듈을 설치해 보겠습니다. 가상 환경 생성과 비슷한데, script 만 init 에서 install 로 변경해 주면 됩니다.

 

> docker run -v ./app:/opt/app -v ./scripts/install.sh:/entrypoint.sh -it --rm python:3.12.2-slim-bullseye sh ./entrypoint.sh

 

 

다음 단계인 collect static 을 실행합니다. 이번에는 볼륨매핑 옵션에 nginx의 static 파일 위치를 지정해 주어야 합니다.

> docker run -v ./app:/opt/app -v /opt/docker/nginx/static:/opt/app/static -v ./scripts/collectstatic.sh:/entrypoint.sh -it --rm python:3.12.2-slim-bullseye sh ./entrypoint.sh

 

제대로 실행이 되었다면 /opt/docker/nginx/static 폴더에 static 파일들이 업데이트 되어야 합니다.

 

 

모델 업데이트는 script만 db로 변경해 줍니다. database를 사용하는 경우에는 db에 필요한 테이블이 생성이 되는데, 여기서는 db.sqlite3 파일이 생성됩니다.

 

> docker run -v ./app:/opt/app -v ./scripts/db.sh:/entrypoint.sh -it --rm python:3.12.2-slim-bullseye sh ./entrypoint.sh

 

 

django app이 잘 실행되는지 테스트를 해 봅니다. 아래 커맨드를 실행하고, 해당 서버로 접속을 해 봅니다.

> docker run -v ./app:/opt/app -v ./scripts/run_test.sh:/entrypoint.sh -p 8000:8000 -it --rm python:3.12.2-slim-bullseye sh ./entrypoint.sh

 

 

아래 화면은 Ubuntu desktop 에서 실행했을 때의 결과인데, django 404 error 페이지가 나오지만 실행은 잘 되는 것을 알 수 있었습니다. 실제로는 localhost 대신 서버 주소를 입력해야합니다.

 

 

그리고, admin 페이지는 아래와 같이 나옵니다.

 

 

이제 정식으로 django app 을 실행하기 위해서 docker-compose.yaml 파일을 아래와 같이 작성합니다.

 

/opt/docker/python/docker-compose.yaml

version: "3.7"
services:
  python:
    image: python:3.12.2-slim-bullseye
    volumes:
      - ./app:/opt/app
      - ./scripts/run.sh:/entrypoint.sh
    command: sh entrypoint.sh
    ports:
      - "8000:8000"

 

 

그리고 아래 명령어를 이용하여 컨테이너를 실행합니다.

> docker compose up -d

 

 

django app 이 asgi 형태로 실행되고 있어서, static 파일들 (css, image 등) 이 화면에 표현되지 않습니다.

 

테스트는 잘 실행이 되었지만, docker compose 실행이 제대로 되지 않는다면, 아마도 asgi 파일의 위치 문제일 가능성이 큽니다. run.sh 파일을 편집에서 해당 프로젝트에서 asgi 파일이 있는 경로를 지정해 주면 됩니다.

 

static 파일 문제를 해결하기 위해서 nginx를 셋업하도록 하겠습니다.

 

 

nginx 셋업

nginx도 docker로 이용할 예정이기 때문에 별다른 설치는 필요하지 않습니다. 

nginx에서는 static 파일에 대한 요청을 처리하고, 나머지 요청은 django app으로 보내 줍니다. 실제로는 ssl 처리 등의  복잡한 기능이 필요하지만, 여기서는 아래와 같이 간단한 설정 파일을 준비합니다. 여기서 proxy_pass에 사용한 172.17.0.1 은 docker의 기본 host 주소 입니다. 원래는 docker network 을 이용해야 하지만, 간단한 예시이기 때문에, docker 기본 host 아이피를 적어주었습니다.

 

/opt/docker/nginx/conf/app.conf

server {
    listen 80;
    listen [::]:80;
    server_name localhost;

    location /static {
        alias /opt/app/static;
    }

    location / {
        proxy_pass http://172.17.0.1:8000/;
    }
}

 

 

그리고 docker-compose.yaml 파일을 아래와 같이 작성합니다.

 

/opt/docker/nginx/docker-compose.yaml

version: "3.7"
services:
  python:
    image: nginx:1.24.0
    volumes:
      - ./static:/opt/app/static
      - ./conf/app.conf:/etc/nginx/conf.d/app.conf
    ports:
      - "80:80"
      - "443:443"

 

 

아래 명령어를 이용하여 컨테이너를 실행합니다.

> docker compose up -d

 

 

그리고 나서 browser에서 확인해 보면.. 아래와 같은 에러가 나옵니다. 

 

 

에러 내용은.. 허용되지 않는 host 라는 건데요.. 해결하기 위해서는 django app의 소스코드를 수정해야 합니다.

 

/opt/docker/python/app/config/settings.py 파일을 열어서 28번째 줄을 다음과 같이 변경합니다. 

 

실제 운영환경에서는 이런 식의 소스 코드 변경을 막기위해서 이러한 설정 값은 모두 환경변수에서 읽어서 처리하게 해야 합니다.

 

 

그리고 python (django app) 의 docker 를 새로 띄우면, 아래와 같이 잘 나오게 됩니다.

 

 

눈치 빠르신 분은 이미 알아채셨겠지만.. 접속 주소가 localhost:8000 에서 localhost 로 변경이 되었습니다. nginx 가 연결을 해주기 때문에 이제는 localhost 로 접속하면 됩니다. 기존의 8000 포트는 iptables 혹은 firewall 등을 이용해서 외부에서 접근하는 것을 막아 두는 것이 좋습니다.

 

반응형

'프로그래밍 > Python - Django' 카테고리의 다른 글

Django URL patterns  (0) 2024.03.17
Django Query Tips - User, Group, Permission  (0) 2024.03.02
Django - Proxy Models  (0) 2023.02.23
Django Tutorial Part 1 - HelloWorld  (0) 2022.11.01
Django - 프로젝트 시작하기  (0) 2022.10.28
반응형

이번 포스트는 앱 배포에 관한 것으로, docker 환경에 구축된 jenkins를 이용해서, git repository 에 저장된 소스를 가지고 와서 docker 이미지를 빌드하고, private docker registry 에 배포하는 과정에 대해서 정리해 보았습니다.

 

 

서버 환경

먼저 서버를 준비해야 하는데, 어차피 docker로 배포가 될 예정이기 때문에, 테스트 환경은 Virtual Box 에 설치한 Ubuntu 22.04 LTS 상에서 docker를 설치해서 진행했습니다.

 

 

Docker 설치

대부분 application은 docker 상에서 구동될 예정이기 때문에 먼저 docker를 설치합니다.

 

설치과정은 다음 링크에 자세히 나와 있습니다.

Install Docker Engine on Ubuntu | Docker Documentation

 

1. 기존에 설치된 버전을 삭제합니다.

sudo apt-get remove docker docker-engine docker.io containerd runc

 

2. apt 패키지 인덱스를 업데이트 하고 필요한 패키지를 설치합니다.

sudo apt-get update
sudo apt-get install ca-certificates curl gnupg lsb-release

 

3. Docker의 GPG Key를 추가합니다.

sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

 

4. Docker 설치를 위한 apt repository를 세팅합니다.

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

 

5. apt 패키지를 다시 업데이트 하고, docker를 설치합니다.

sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin

 

Docker Registry

docker registry는 docker 이미지를 빌드한 후에 배포하기 위해서 사용합니다. docker.io 등에서 제공하는 public registry를 사용하는 경우에는 이 과정을 생략해도 좋습니다.

 

docker-compose.yml 파일을 생성해서 다음과 같이 작성합니다.

version: '3'

services:
  registry:
    container_name: docker_registry
    image: registry:2
    restart: unless-stopped
    ports:
    - "5000:5000"
    environment:
      REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
    volumes:
      - ./data:/data

 

docker-compose 명령어 혹은 docker 명령어로 registry 서버를 시작합니다.

 

docker-compose 가 설치되어 있는 경우

docker-compose up -d

 

docker 명령어를 사용하는 경우

docker compose up -d

 

docker registry 의 경우 https를 사용하는 것이 기본이지만.. 테스트 환경 혹은 private 네트워크 환경에서는 굳이 https를 사용할 필요가 없어서 http를 사용할 경우에는, 아래와 같이 설정을 해 줍니다.

 

1. /etc/docker/daemon.json 파일 오픈 (없으면 생성)

2. 아래와 같은 내용을 추가합니다.

{"insecure-registries": ["host:port"]}

3. docker 서비스를 재시작 합니다.

sudo systemctl restart docker

 

혹시 기본 옵션 파일을 인식하지 못한다면, /etc/default/docker 파일에 DOCKER_OPTS="--config-file=/etc/docker/daemon.json" 을 추가하고, docker 서비스를 재시작 합니다.

 

참고 링크

https://stackoverflow.com/questions/49674004/docker-repository-server-gave-http-response-to-https-client

 

 

Jenkins 시작

Jenkins도 별도로 설치하지 않고, docker 컨테이너 형태로 사용을 할 예정인데요, 이런 식으로 사용하는 경우 docker 관련 플러그인을 사용할 때, docker 명령어를 찾지 못하거나 glibc 버전 문제가 발생할 수 있어서, jenkins docker 이미지에  docker를 추가로 설치해서 사용하도록 하겠습니다.

 

먼저 아래와 같이 Dockerfile 파일을 준비합니다. 

FROM jenkins/jenkins:lts
USER root
RUN apt-get update -qq \
    && apt-get install -qqy apt-transport-https ca-certificates curl gnupg2 software-properties-common
RUN curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -
RUN add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/debian \
   $(lsb_release -cs) \
   stable"
RUN apt-get update  -qq \
    && apt-get -y install docker-ce
RUN usermod -aG docker jenkins

 

아래 명령어를 이용해서 이미지를 빌드합니다.

docker image build -t custom-jenkins-docker .

 

Jenkins를 띄울 때도, docker-compose.yml 을 작성해서 띄우도록 하겠습니다.

docker-compose.yml 파일을 다음과 같이 작성합니다.

version: '3'

services:
  jenkins:
    container_name: jenkins
    image: custom-jenkins-docker:latest
    restart: unless-stopped
    privileged: true
    user: root
    ports:
     - "8080:8080"
     - "50000:50000"
    volumes:
     - ./data:/var/jenkins_home
     - /var/run/docker.sock:/var/run/docker.sock

 

docker-compose 명령어 혹은 docker 명령어로 jenkins 서버를 시작합니다.

 

docker-compose 가 설치되어 있는 경우

docker-compose up -d

 

docker 명령어를 사용하는 경우

docker compose up -d

 

 

Jenkins 설정

웹 브라우저를 이용해서 http://localhost:8080 으로 접속합니다. 참고로 저는 virtual box의 host 네트워크 설정으로 host PC에서 IP (192.168.56.101) 로 접근할 수 있게 설정하였습니다.

 

처음 실행시 아래와 같은 화면이 나옵니다.

 

화면에 나온 설명대로 docker 컨테이너 내에서 /var/jenkins_home/secrets/initialAdminPassword 파일을 열어보면 초기 비밀번호를 확인할 수 있습니다. 해당 파일은 docker-compose 로 띄울 때, .data 폴더를 /var/jenkins_home 폴더로 매핑시켜 두었기 때문에,  Ubuntu 서버 내에서 .data/secrets/initialAdminPassword 파일을 열어보아도 동일한 결과를 얻을 수 있습니다.

그 외에는 docker 컨테이너 log를 이용해서 아래와 같이 초기 비밀번호를 확인할 수도 있습니다.

docker logs jenkins

 

다음 화면에서는 Install suggested plugins를 클릭해서 기본 플러그인들을 설치합니다.

 

다음 화면에서는 Admin User를 생성해도 되지만 귀찮으시면 Skip 을 눌러서 넘길 수도 있습니다. (Skip시 initial password를 계속 사용하게 됩니다.)

 

Jenkins URL을 세팅하고, 시작합니다. 

 

 

Jenkins 화면에서 Jenkins 관리 > 플러그인 관리 > Available plugins 를 차례로 클릭합니다.

 

검색창에서 docker를 입력합니다.

 

Docker, Docker Commons, Docker Pipeline, Docker API, docker-build-step 를 체크하고, Download now and install after restart 를 클릭합니다.

 

 

설치 후 Jenkins 재시작을 체크하면, Jenkins가 재시작 됩니다.

 

마지막으로 docker socket을 세팅해 줍니다.

Jenkins 관리 > 시스템 설정을 차례로 클릭합니다.

스크롤해서 Docker Builder 항목을 찾아가서 Docker server REST API URL에 아래와 같이 "unix:///var/run/docker.sock" 을 입력합니다.

 

 

빌드 테스트

이제 Jenkins 에 Pipeline 아이템을 추가해서 빌드 테스트를 진행 해보겠습니다.

 

Jenkins Dashboard에서 새로운 Item을 클릭합니다.

 

적당한 이름을 입력하고, Pipeline 을 선택하고 OK 버튼을 눌러서 넘어갑니다.

 

먼저, Docker 이미지에 버전을 태깅하기 위해서 BUILD_NUMBER를 인자로 받도록 합니다.

 

General 섹션에서 "이 빌드는 매개변수가 있습니다" 를 체크하고, String Parameter를 선택하고, 매개변수 명에 "BUILD_NUMBER" 라고 적습니다.

 

쭉 아래로 내려서 Pipeline 섹션에 빌드 스크립트를 작성합니다.

아래와 비슷하게 작성하면 됩니다.

 

 

스크립트 내용은 아래와 같습니다.

node {
    def app
    def imgName = "customapps/django_test"
    stage('Clone Repository') {
        git 'https://github.com/shineum/django_sample.git'
    }
    stage('Build Image') {
        app = docker.build("${imgName}:${env.BUILD_NUMBER}")
    }
    stage('Push Image') {
        docker.withRegistry('http://192.168.56.101:5000') {
            app.push("${env.BUILD_NUMBER}")
            app.push("latest")
        }
    }
    stage('Clean Up') {
        sh "docker images ${imgName} -q | xargs docker rmi -f > /dev/null 2>&1 || true"
    }    
}

 

스크립트 내용은 대략 다음과 같습니다.

 

1. Clone Repository

github에서 소스 코드를 가지고 옵니다.

 

2. Build Image

docker 이미지를 빌드합니다. Jenkins 서버가 아니라 docker를 설치한 Ubuntu 서버에 이미지가 생성됩니다.

 

3. Push Image

해당 docker 이미지를 private registry 서버에 push 합니다. (registry 서버는 virtual box 에서 host 전용 네트워크를 이용해서 ip를 설정하였습니다.)

처음에는 빌드 버전대로 하나 올리고, 새 빌드를 latest 로 세팅합니다.

 

4. Clean Up

Ubuntu 서버에는 앱 이미지가 필요 없기 때문에 불필요한 이미지들을 정리합니다. 이 때, 앱을 빌드할 때 사용되는 base 이미지들을 같이 삭제하게 되면, 빌드 시간이 길어지기 때문에, 앱 배포 이미지만 삭제합니다. 

 

스크립트 작성이 끝났으면 저장하고 빠져나옵니다.

 

 

파라미터와 함께 빌드를 클릭하고, BUILD_NUMBER를 입력합니다.

 

이미지 빌드는 base image를 다운로드해야 하며, 앱에서 필요로 하는 모듈도 다운로드해야 하기 때문에 시간이 조금 걸립니다.

 

빌드가 완료되면 아래와 비슷한 결과가 출력됩니다.

 

확인을 위해 registry 서버에 접속해보면,

 

먼저 카탈로그 확인

http://192.168.56.101:5000/v2/_catalog

 

그리고, 아래와 같이 빌드 관련 정보를 확인할 수 있습니다.

http://192.168.56.101:5000/v2/customapps/django_test/tags/list

다음 명령으로 릴리즈 된 docker 이미지를 registry 서버에서 pull 할 수 있습니다. (latest 대신 버전을 적어줘도 됩니다.)

docker pull 192.168.56.101:5000/customapps/django_test:latest

 

 

빌드 실행

마지막으로 조금 전에 빌드한 이미지를 앱 서버에 배포해서 실행해 보겠습니다.

실제 운영 환경에서는 kubernetes 나 docker swarm 등을 사용하기 때문에 조금 더 복잡하겠지만.. 여기서는 단순하게 Ubuntu 서버에서 docker 이미지를 실행해 보겠습니다.

 

Jenkins Dashboard에서 새로운 Item을 클릭합니다. 이번에도 적당한 이름을 지정하고 Pipeline을 선택합니다.

 

General 섹션에서 "이 빌드는 매개변수가 있습니다" 를 체크하고, String Parameter를 선택하고, 매개변수 명에 "BUILD_NUMBER" 라고 적습니다. 그리고 이번에는 Default Value 에 "latest" 를 적어 줍니다.

 

쭉 아래로 내려서 Pipeline 섹션에 빌드 스크립트를 작성합니다.

아래와 비슷하게 작성하면 됩니다.

 

 

스크립트 내용은 아래와 같습니다.

node {
    def containerName = "cn_django_test"
    def imgName = "customapps/django_test"
    def regServer = "192.168.56.101:5000"
    stage("Stop App") {
        sh "docker stop ${containerName} || true && docker rm ${containerName} || true"
    }
    stage("Clean Up") {
        sh "docker images ${imgName} -q | xargs docker rmi -f > /dev/null 2>&1 || true"
    }
    stage("Start App") {
        sh "docker run -it -d -p 8000:8000 --name ${containerName} ${regServer}/${imgName}:${env.BUILD_NUMBER}"
    }
}

 

스크립트 내용은 대략 다음과 같습니다.

 

1. Stop App

기존에 실행 중인 앱을 정지 합니다.

 

2. Clean Up

기존에 실행 할 때 사용했던 app build 이미지를 제거 합니다.

 

3. Start App

지정한 버전의 app build 이미지를 registry로부터 pull하고 app을 구동합니다.

 

 

스크립트 작성이 끝났으면 저장하고 빠져나옵니다.

 

 

파라미터와 함께 빌드를 클릭하고, BUILD_NUMBER는 "latest"로 두고 실행합니다.

 

빌드가 잘 완료되었는지 확인하고,

 

App URL로 접속해보면, django 앱이 실행되고 있음을 확인할 수 있습니다.

 

 

이상으로 포스트를 마치도록 하겠습니다. 

반응형
반응형

이번 시간에는 node.js 를 이용해서 min.io 스토리지에 접근해서 파일을 읽고, 쓰는 예제 코드를 작성해 보겠습니다.

 

이번 포스트는 작성시 아래 url 을 참고하였습니다.

https://northflank.com/guides/connecting-to-a-minio-database-using-node-js

 

Connecting to a MinIO database using Node.js — Northflank

MinIO is a highly-available, S3 compatible object storage solution. Through this guide you will learn how to connect a MinIO instance to your Node.js project.

northflank.com

 

먼저 node.js 를 설치해야 합니다. 설치가 필요하신 분들은 아래 사이트를 참고하셔서 설치하시기 바랍니다.

https://nodejs.org/

 

Node.js

Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.

nodejs.org

 

다음으로는 node.js 프로젝트를 생성합니다.

 

폴더하나 생성하고, 폴더로 가서 아래와 같이 입력합니다.

> npm init

 

몇 가지 물어보는 것에 성실히 답을 하면 프로젝트가 생성됩니다. 그리고나서 아래 명령어들을 차례로 입력해서, 필요한 모듈을 설치합니다.

> npm install
> npm install minio

 

minio 모듈은 minio 서버에 접속해서 필요한 기능을 수행할 수 있게 해주는 모듈입니다.

 

 

min.io 서버에 접속하기 위해서는 서버의 host, port 와 함께, access key, secret key 정보가 필요합니다.

 

min.io 에서 javascript Client API 및 예제를 제공하고 있으므로, 아래 링크 참조하세요.

https://docs.min.io/docs/javascript-client-api-reference.html

 

MinIO | JavaScript Client API Reference

JavaScript Client API Reference Initialize MinIO Client object. MinIO var Minio = require('minio') var minioClient = new Minio.Client({ endPoint: 'play.min.io', port: 9000, useSSL: true, accessKey: 'Q3AM3UQ867SPQQA43P2F', secretKey: 'zuf+tfteSlswRu7BJ86wek

docs.min.io

 

min.io 서버에 접속하기 위한 코드는 다음과 같습니다. 여기서 필요한 세팅 정보를 변경해 줘야 합니다.

var Minio = require('minio')

var minioClient = new Minio.Client({
    endPoint: 'play.min.io',
    port: 9000,
    useSSL: true,
    accessKey: 'Q3AM3UQ867SPQQA43P2F',
    secretKey: 'zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG'
});

 

먼저 endPoint 는 min.io 서버의 IP 주소를 입력하면 됩니다. 

port는 min.io 서비스의 port를 적어주면 됩니다. 서비스 default 값은 9000 입니다.

useSSL은 실제 서비스에서는 true 로 해줘야겠지만,  SSL 설정이 되어 있지 않은 테스트 환경에서는 false 로 지정합니다.

나머지 access key 와 secret key 는 min.io 콘솔에서 생성합니다.

 

콘솔에 로그인한 후에, 오른쪽 메뉴에서 Identity 를 선택하고, Service Accounts 를 선택합니다.

 

화면 오른쪽 상단에 있는 Create service account 버튼을 클릭합니다. 아래와 같이 Access Key와 Secret Key가 생성됩니다. 

 

Create 버튼을 눌러서 생성하면, 아래처럼 Access Key와 Secret Key가 공개되는데, Secret Key는 여기서만 보여주고, 다시 확인이 불가능하니, Download for import 버튼을 눌러서 백업해 두는 것이 좋습니다.

 

Access Key와 Secret Key 가 생성되고 나면, 연결 설정 정보들을 변경해줍니다.

 

그리고 아래와 같이 코드를 작성해서, "test-bucket" 을 생성하고, bucket 리스트를 받아와서 console에 출력해 봅니다.

const bucketName = "test-bucket";

(async () => {
  console.log(`Creating Bucket: ${bucketName}`);
  await minioClient.makeBucket(bucketName, "hello-there").catch((e) => {
    console.log(
      `Error while creating bucket '${bucketName}': ${e.message}`
     );
  });

  console.log(`Listing all buckets...`);
  const bucketsList = await minioClient.listBuckets();
  console.log(
    `Buckets List: ${bucketsList.map((bucket) => bucket.name).join(",\t")}`
  );
})();

 

다음 코드는 문자열을 텍스트 (파일) 오브젝트를 생성해서 스토리지에 저장하는 예제입니다.

(async () => {
  // create object with string data
  const objectName = "file.txt";
  const result = await minioClient
    .putObject(bucketName, objectName, "Hello There!")
    .catch((e) => {
      console.log("Error while creating object: ", e);
      throw e;
    });

  console.log("Object uploaded successfully: ", result);
})();

 

다음 코드는 파일을 읽어서 스토리지에 저장하는 예제입니다.

const fs = require('fs');

(async () => {
  // create object from file data
  const objectFileName = "file-object.txt";
  const fileData = fs.readFileSync("./file.txt");
  const submitFileDataResult = await minioClient
    .putObject(bucketName, objectFileName, fileData)
    .catch((e) => {
      console.log("Error while creating object from file data: ", e);
      throw e;
    });

  console.log("File data submitted successfully: ", submitFileDataResult);
})();

 

마지막으로 스토리지에 저장되어 있는 오브젝트를 읽어와서 로컬 폴더에 저장하는 예제입니다.

const fs = require('fs');

(async () => {
  // read object in chunks and store it as a file
  const fileStream = fs.createWriteStream("./read-in-chunks.txt");
  const fileObjectKey = "file-object.txt";

  const object = await minioClient.getObject(bucketName, fileObjectKey);
  object.on("data", (chunk) => fileStream.write(chunk));

  object.on("end", () => console.log(`Reading ${fileObjectKey} finished`));
})();

지금까지 node.js 코드를 이용해서, min.io 스토리지에 bucket 을 생성하고, bucket 리스트를 받아오고, (파일) 오브젝트를 생성하고, 읽어오는 예제들을 살펴보았습니다. 

여기에 나온 예제들은 예외처리가 제대로 되어 있지 않아서, 실제 사용시에는 조금 더 주의를 기울여서 살펴봐야 합니다.

반응형
반응형

먼저 min.io 는 무엇인가? 그리고 어디에 쓰면 좋은가? 에 대해서 살펴보도록 하겠습니다.

 

https://min.io/

 

MinIO | High Performance, Kubernetes Native Object Storage

MinIO's High Performance Object Storage is Open Source, Amazon S3 compatible, Kubernetes Native and is designed for cloud native workloads like AI.

min.io

 

홈페이지에 따르면, min.io는 (aws) S3와 호환되는 고성능의 오브젝트 스토리지 라고 소개하고 있습니다. 즉, 스토리지 서비스를 구축하는데 사용할 수 있는 오픈 소스 솔루션 입니다. S3와 사용법이 거의 유사하게 되어 있어서, S3를 써 보셨던 분들은 매우 쉽게 사용이 가능하며, 스토리지를 처음 써보시는 분들은 약간의 적응이 필요합니다.

 

서비스를 시작하는 방법은 여러가지가 있지만, 저는 docker를 사용해서 서비스를 시작해 보겠습니다. (docker 설치 필요)

 

min.io 서비스를 시작하기 위해서는 docker를 사용하면 되는데, min.io 에서는 podman 커맨드를 제시하고 있어서 혼선을 주고 있습니다. podman 을 별도로 설치하기 귀찮아서 docker-compose.yml 파일을 아래와 같이 작성해 보았습니다.

 

version: '3'
services:
  s3:
    image: minio/minio
    ports:
      - 9000:9000
      - 9001:9001
    environment:
      MINIO_ROOT_USER: admin
      MINIO_ROOT_PASSWORD: changeme
    volumes:
      - ./storage/minio:/data
    command: server /data --console-address ":9001"

 

서비스 명은 편의상 s3로 하였습니다. 그리고, docker에서 사용할 image 를 지정해 주었고 (minio/minio), 서비스에서 사용될 포트를 매핑해 주었습니다. (9000, 9001)

환경변수로 user, password 를 지정해 주었으며, volume을 지정하여 재시작을 해도 기존에 저장했던 스토리지 정보가 남을 수 있게 해 주었습니다.

시작 커맨드는 버전에 따라 약간씩 상이하다고 하니, 추후에는 변경이 될 수도 있습니다.

 

커맨드 윈도우에서 아래 명령어를 이용해서 서비스를 시작합니다.

> docker-compose -f docker-compose.yml up -d

 

도커 컨테이너가 제대로 실행되어 돌아가면, 브라우저를 열어서 http://localhost:9000 으로 접속을 시도합니다.

요청은 http://localhost:9001로 redirect 되며, 아래와 같은 admin 페이지 로그인 창이 뜹니다.

위의 docker-compose.yml 파일에 설정했던, username, password 를 이용해서 로그인을 합니다.

 

로그인을 하면, 아래와 같은 화면이 나옵니다.

 

위의 화면에서 우측 상단의 Create Bucket 버튼을 클릭해서 Bucket을 생성해 봅니다.

Bucket Name 에 'test'를 입력하고, Create Bucket 버튼을 클릭하여 bucket을 생성합니다. 제대로 생성되면 아래와 같은 화면이 나오게 됩니다.

 

생성된 bucket 에 파일을 드래그해서 업로드 해 봅니다. 아래와 같은 화면이 나오면서 파일이 올라간 것이 화면에 표시됩니다. 업로드 버튼을 클릭해서 폴더도 생성할 수 있고, 파일을 업로드 할 수도 있습니다.

 

업로드 된 파일을 클릭해보면, 화면 우측에 파일을 다운로드, 공유, 삭제하거나 정보를 확인 할 수 있는 창이 나타납니다.

 

Share 아이템을 클릭하면 아래와 같이 특정 기간 동안 유효한 URL을 생성하여 파일을 공유할 수 있습니다.

 

이번 시간에는 docker를 이용해서 min.io 서비스를 설치하고, bucket을 생성하고, 간단하게 파일 업로드 및 공유 기능에 대해서 살펴 보았습니다. 다음 시간에는 node.js를 이용해서 프로그래밍으로 bucket 을 관리하고, 파일 업로드 및 다운로드를 하는 예시를 살펴 보겠습니다.

반응형

+ Recent posts