컴퓨터/도커

3. 도커 실습

sidedoor 2024. 8. 3. 19:19

pyenv설치

 

가상환경을 왜 만들어야하는지는 다음 참조

https://leedominico.tistory.com/2

 

아나콘다 jupyter notebook 가상 환경 만들기

먼저 왜 가상 환경을 만들어야 할까? 기본적으로 파이썬이나 다른 라이브러리들은 수시로 업데이트가 되는데 이러한 것들 중에서 서로 얽혀있는 경우가 있어서 원래는 잘 되다가 나중에 업데이

leedominico.tistory.com

 

# pyenv설치 위한 프로그램 설치
sudo apt install -y build-essential libssl-dev zlib1g-dev libncurses5-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev

# pyenv설치
curl https://pyenv.run | bash

# pyenv환경 설정
export PYENV_ROOT="$HOME/.pyenv"
command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"

 

위처럼 pyenv를 설치하여 파이썬 가상환경을 관리할 수 있게 한다.

 

파이썬 3.11.6 버전 설치후 py3_11_6이라는 가상 환경을 생성

 

가상환경 실행

가상환경은 위처럼 실행을 할 수 있고, 실행을 하면 앞에 어떤 가상 환경에서 실행중인지 표기가 된다.

 

# 가상환경 실행
pyenv activate [가상환경 이름]

# 가상환경 종료
source deactivate

 

tree명령어는 디렉토리와 파일을 트리 구조로 시각적으로 보여주는 도구이다.

 

tree ./ -L 3

 

tree명령어로 다음과 같이 입력을 하면 현재 디렉토리에서 트리구조의 깊이 제한을 3으로 한 결과를 출력한다.

 

 

django 실행위한 네트워크 설정

 

포트 포워딩은 네트워크 주소 변환의 일종으로, 외부 네트워크에서 특정 포트로 들어오는 데이터를 내부 네트워크의 특정 장치나 포트로 전달하는 방법이다.

여기서는 호스트 포트 8000번과 서버의 ip인 10.0.2.4의 8000번 포트를 연결하고 호스트 포트 80번과 서버의 ip인 10.0.2.4의 8000번 포트를 연결한다.

 

YAML

 

YAML은 TAML Ain't Markup Language의 줄임말로 데이터를 직관적이고 사람이 읽기 쉬운 형태로 표현하기 위한 데이터 직렬화 형식이다.

yaml파일 생성
yaml의 문법

YAML파일은 위처럼 python의 딕셔너리 형식과 유사하게 사용할 수 있다.

open을 통해서 파일을 불러온 다음 key들의 value를 확인할 수 있고, yaml파일에서 '-' 기호를 사용해서 리스트 형태로 값을 저장할 수 있다.

 

# 다중 행 문자열
description: >
  This is a long description
  that spans multiple lines.
  It will be displayed as a single
  continuous string with spaces.

# 결과
This is a long description that spans multiple lines. It will be displayed as a single continuous string with spaces.

# 다중 행 문자열 2
description: |
  This is a long description
  that spans multiple lines.
  Each line will be preserved
  as it is written.

# 결과
This is a long description
that spans multiple lines.
Each line will be preserved
as it is written.

 

그리고 이렇게  다중 행 문자열을 작성하면 각각 줄 바꿈 처리 방식이 달라지는 것을 알 수 있다.

Django 실행

django를 실행하고 myapp이라는 프로젝트를 생성하여 구조를 확인하면 위와 같은 결과를 볼 수 있다.

여기서 setting.py파일에 아래 부분을 수정해주면 외부에서 접근할 수 있도록 접근 허용 호스트를 설정해준다.

 

접근 가능하도록 허용 호스트 설정

 

그 후 8000번 포트를 사용해서 프로젝트를 실행해주면 아래와 같은 결과가 나오고 웹으로 접속을 하면 접속이 잘 되는것을 볼 수 있다.

 

접속 결과

그 후 django 프로젝트를 컨테이너 이미지로 빌드 해보면 도커 이미지를 생성하기 위해 필요한 설치 파일 목록인 requirements.txt파일을 생성한다.

그리고 도커 이미지 파일을 생성하기 위한 명령어를 모아둔 Dockerfile을 생성한다.

 

# requirements.txt파일 생성

django==4.2.7

# Dockerfile 생성

FROM python:3.11.6 # 베이스 이미지

WORKDIR /usr/src/app # 해당 작업 디렉토리 전환

COPY . . # [호스트 파일경로]에 있는 파일을 [이미지 파일 경로]로 복사

RUN python -m pip install --upgrade pip # 이미지 빌드시 실행
RUN pip install -r requirements.txt

WORKDIR ./myapp

CMD python manage.py runserver 0.0.0.0:8000 # 컨테이너 실행시 실행
EXPOSE 8000

# 도커 이미지 빌드

docker image build . -t myweb01

# 생성한 도커 이미지 컨테이너 형태로 배포

docker container run -d -p 8000:8000 myweb01 # -p [도커 호스트 포트][컨테이너 포트]

 

웹 브라우저를 실행해 접속을 하면 아래와 같이 실행중인 컨테이너의 ip주소를 확인 할 수 있다.

 

위 과정을 이미지로 나타내면 다음과 같다

Nginx, django 연동

 

Nginx는 웹서버로 HTML, CSS, JavaScript, 이미지 파일 등과 같은 정적 콘텐츠를 제공하는 데 최적화되어 있다.

따라서 django와 연동을 통해서 배포를 할 수 있게 된다.

 

도커 이미지 빌드를 위한 Dockerfile을 다음과 같이 생성하고 이미지를 빌드한다.

 

# Dockerfile

FROM nginx:1.25.3
CMD ["nginx", "-g", "daemon off;"]

# 도커 이미지 빌드

docker image build . -t mynginx01

빌드한 이미지를 활용해 컨테이너 실행

 

Nginx 컨테이너 실행 결과

위와 같이 하면 80번 포트로 접속했을 때 Nginx가 잘 실행되는 것을 볼 수 있다.

 

이제 앞에서 생성한 django와 Nginx를 gunicorn을 통해서 연동해야한다.

아래 코드를 보면 djangotest는 django를 이용해 생성하는데 Nginx가 80포트로 받은 요청을 djangotest컨테이너의 8000포트로 전송해준다.

 

# django에서 requirements.txt

django==4.2.7
gunicorn==20.1.0


# django에서 Dockerfile

FROM python:3.11.6

WORKDIR /usr/src/app

COPY . .

RUN python -m pip install --upgrade pip
RUN pip install -r requirements.txt

WORKDIR ./myapp
CMD gunicorn --bind 0.0.0.0:8000 myapp.wsgi:application

EXPOSE 8000

# default.conf파일

upstream myweb{
    server djangotest:8000;
}

server{
    listen 80;
    server_name localhost;

    location /{
        proxy_pass http://myweb;
    }
}

# Nginx의 Dockerfile

FROM nginx:1.25.3
RUN rm /etc/nginx/conf.d/default.conf
COPY default.conf /etc/nginx/conf.d/
CMD ["nginx", "-g", "daemon off;"]

 

이제 아래와 같이 연결을 하면 호스트 웹 브라우저에서 127.0.0.1:80으로 연결을 하면 포트포워딩을 통해 10.0.2.4:80으로 트래픽이 전달되고, nginxtest를 통과한 후 djangotest컨테이너에 접속하여 django서비스를 활용할 수 있게 된다.

 

 

PostgreSQL 연동

방금 진행한 과정과 유사하게 진행을 해주면 된다.

먼저 Dockerfile을 다음과 같이 만들어 postgres위에서 동작을 하게 만들어 준다.

그리고 이미지를 빌드하고 컨테이너를 실행하면 동일하게 실행 할 수 있다.

 

# Dockerfile

FROM postgres:15.4

# 도커 컨테이너 실행

docker container run -e POSTGRES_PASSWORD=mysecretpassword --mount type=volume,source=myvolume03,target=/var/lib/postgresql/data -d mypostgres03

 

그럼 이제 앞에서 진행한 내용을 모두 연동을 해보자

myDjango폴더 내부의 myapp/myapp위치에 있는 settings.py파일을 다음 이미지와 같이 수정을 해야 하는데 이는 컨테이너를 연동하기 위한 과정으로 HOST항목에 postgreSQL컨테이너 이름을 쓰면 된다.

 

 

이제 앞의 과정과 동일하게 requirements.txt파일, Dockerfile파일을 만들고 도커 이미지를 빌드하면 된다.

그렇게 하면 아래의 이미지와 같은 방식으로 연결이 된다.

 

전체 프로세스

# requirements.txt
django==4.2.7
gunicorn==20.1.0
psycopg2==2.9.9 # postgreSQL을 파이썬을 통해 활용

# 컨테이너 실행
docker container run --name postgrestest --network mynetwork03 -e POSTGRES_PASSWORD=mysecretpassword --mount type=volume,source=myvolume03,target=/var/lib/postgresql/data -d mypostgres03

# django 컨테이너 실행
docker container run -d --name djangotest --network mynetwork03 myweb03

# Nginx 컨테이너 실행
docker container run -d --name nginxtest --network mynetwork03 -p 80:80 mynginx03

 

위의 코드를 실행하면 아래와 같이 djangotest컨테이너 내부에 접속해서 셸을 실행하여 연결상태를 볼 수 있다.

 

 

이제는 postgreSQL을 가상머신의 로컬에 설치한 뒤 이를 Nginx와 django컨테이너와 연동을 해보자

 

# PostgreSQL설치
sudo sh -c 'echo "deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
sudo apt update
sudo apt -y install postgresql

 

postgreSQL을 설치하고 아래와 같이 명령어를 입력하면 상태가 activate로 잘 실행되고 있음을 볼 수 있다.

 

그 후 아래와 같이 /etc/postgresql/16/main에 있는 pg_hba.conf에 외부 접근을 허용하기 위해 아래 이미지와 같이 코드를 추가한다.

 

그리고 추가적으로 주석처리되어있는 listen_addresses부분을 다음과 같이 수정하여 서버가 어떤 클라이언트의 요청을 수락할지 수정을 해준다.

 

이후로는 이전과 동일한 과정을 진행하면 되는데 이때는 가상머신의 로컬과 연결되기 때문에 docker0의 IP주소를 확인하고 해당 주소로 연결할 수 있게 수정해야한다.

따라서 아래와 같이 HOST의 주소를 docker)의 IP주소로 변경해줘야 한다.

 

그 다음 과정은 이전과 동일하게 진행하면 된다.

위의 모든 과정을 실행한 내용은 다음 이미지로 표현할 수 있다.

 

도커 컴포즈를 활용한 컨테이너 실행

도커 컴포즈는 다중 컨테이너 Docker 애플리케이션을 정의하고 실행하기 위한 도구이다.

도커 컴포즈를 사용하면 하나 이상의 컨테이너를 쉽게 관리할 수 있으며, 각 컨테이너의 설정을 하나의 YAML 파일에 정의할 수 있다.

이로 인해 복잡한 애플리케이션 환경을 설정하고 실행하는 작업이 간단해진다.

 

docker-compose설치

 

 

# docker-compose.yml파일 작성

version: "3"	# 컴포즈 파일 포맷 버전

services:	# 실행하고자 하는 서비스 목록
  djangotest: 	
    build: ./myDjango03	# 이미지 빌드할 디렉토리 경로
    networks:		
      - composenet01
    depends_on:	# 컨테이너 실행 순서로 만약 postgrestest가 입력되어 있다면 해당 컨테이너를 먼저 실행시킨 후 djangotest가 나중에 실행
      - postgrestest
    restart: always # 컨테이너가 정지되면 재실행

  nginxtest:		
    build: ./myNginx03
    networks:
      - composenet01
    ports:	# [도커 호스트 포트]:[컨테이너 포트]
      - "80:80"
    depends_on:
      - djangotest
    restart: always

  postgrestest:
    build: ./myPostgres03
    networks:
      - composenet01
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: mysecretpassword
      POSTGRES_DB: postgres
    volumes:	# 도커 볼륨을 사용해 해당 경로에 마운트
      - composevol01:/var/lib/postgresql/data
    restart: always	

networks:
  composenet01:

volumes:	
  composevol01:

 

이제 docker-compose파일을 활용해서 이미지를 빌드하고 컨테이너를 실행해보면 다음과 같다.

 

# 도커 컴포즈 YAML 파일이 포함하는 컨테이너를 모두 실행
docker compose up -d --build

 

실행 결과는 다음과 같이 나오고 잘 실행되고 container까지 잘 나온것을 볼 수 있다.

 

 

이제 종료를 하려면 아래와 같이 입력을 해주면 실행했던 컨테이너를 정지시킬 수 있다.

 

 

이제 마지막으로 로컬 postgreSQL과 django, Nginx컨테이너를 연결하는 도커 컴포즈를 진행해보자

먼저 docker-compose.yml파일은 다음과 같이 만들수 있다.

 

version: "3"	

services:	
  djangotest:	
    build: ./myDjango04	
    networks:		
      - composenet01
    restart: always

  nginxtest:		
    build: ./myNginx04
    networks:
      - composenet01
    ports:	
      - "80:80"
    depends_on:
      - djangotest
    restart: always

networks:
  composenet01:

 

그리고 위에서 진행한것 처럼 웹 브라우저를 실행한 후 주소창에 주소를 입력하면 접속되는 것을 확인할 수 있다.

그리고 django 컨테이너 내부에도 접속이 가능한 것을 볼 수 있다.

도커를 활용한 Flask 실행

먼저 django에서 한 것 처럼 아래와 같이 네트워크를 먼서 설정해 준다.

 

 

그리고 Flask로 만든 웹 페이지에 접근했을 때 hello world를 출력하는 코드를 작성하여 연결이 잘 되었는지 확인해본다.

 

# Flask로 hello world 출력 코드

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'hello world!'

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8001)

 

이와같이 코드를 짜고 아래처럼 연결을 하면 해당 아이피로 연결이 잘 된 것을 확인할 수 있다.

 

flask 코드 실행 결과

 

이제 앞에서 배운 Nginx를 Flask와 컨테이너 형태로 연동후 실행을 해보겠다.

위의 django에서 진행한 것과 동일하게 Flask와 Nginx의 이미지를 빌드하기 위해서 아래의 코드를 작성해준다.

 

# requirements.txt파일
flask==3.0.0
gunicorn==20.1.0

# Flask의 Dockerfile
FROM python:3.11.6

WORKDIR /usr/src/app

COPY . .

RUN python -m pip install --upgrade pip
RUN pip install -r requirements.txt

WORKDIR ./myapp

CMD gunicorn --bind 0.0.0.0:8001 main:app

EXPOSE 8001

# Nginx의 default.conf파일

upstream myweb{
    server flasktest:8001;
}

server{
    listen 81;
    server_name localhost;

    location /{
        proxy_pass http://myweb;
    }
}

# Nginx의 Dockerfile

FROM nginx:1.25.3
RUN rm /etc/nginx/conf.d/default.conf
COPY default.conf /etc/nginx/conf.d/
CMD ["nginx", "-g", "daemon off;"]

 

그리고 작성한 코드를 바탕으로 아래처럼 각각의 컨테이너를 연동해주면 웹에 잘 표시되는 것을 확인할 수 있다.

 

 

Nginx와 Flask연동 결과

그리고 추가적으로 도커 컴포즈를 활용해 위의 과정을 진행해 보자

docker-compose.yml파일을 다음과 같이 만들어 준다.

 

# docker-compose.yml파일

version: "3"

services:
  flasktest:
    build: ./myFlask03
    networks:
      - composenet03
    restart: always

  nginxtest:
    build: ./myNginx03f
    networks:
      - composenet03
    ports:
      - "81:81"
    depends_on:
      - flasktest
    restart: always

networks:
  composenet03:

 

그리고 작성한 docker-compose파일을 통해서 이미지를 빌드하고 컨테이너를 실행시키면 다음과 같이 실행이 잘 되는것을 볼 수 있다.

 

이제 해당하는 컨테이너의 로그를 확인해보면 다음과 같은데 아래와 같은 명령어를 사용하면 Nginx 컨테이너의 로그를 확인하여 접속 기록을 볼 수 있다.

 

접속 기록 확인