AI 부트 캠프 - Docker 2

Cookie Baking·2024년 12월 9일

AI 부트 캠프 TIL

목록 보기
30/42

뭔가 배포를 관리하는 CI/CD는 이해를 잘 했는데 Docker에 대한 개념은 와닿지 않았다.
다시 해보자


Dockerfile

이미지를 설계도같은 것

명령어
FROM : 베이스 이미지를 선택
MAINTAINER : 이미지를 만든 사람의 정보를 입력
LABEL : 이미지에 메타데이터를 추가
RUN : 이미지에 명령을 실행하여 파일을 추가하거나 삭제
COPY : 파일을 이미지에 복사
EXPOSE : 컨테이너가 노출할 포트를 설정
CMD : 컨테이너가 실행될 때 실행할 명령을 설정
ENTRYPOINT : 컨테이너가 시작할 때, 실행할 명령어를 입력 (컨테이너를 시작할 때마다 실행, 추가적인 명령어 존재 여부와 상관 없이 무조건 실행)
ENV : 환경 변수를 설정, 이미지 안에 각종 환경 변수를 지정
WORKDIR : 작업 디렉터리를 지정
USER : 사용자를 설정
EXPOSE : 컨테이너에서 노출할 포트를 설정

EX. FastAPI 앱을 실행하는 예제

FROM python:3.11

RUN pip install pipenv

WORKDIR /app

ADD . /app/

RUN pipenv --python 3.11
RUN pipenv run pip install poetry
RUN pipenv sync
RUN pipenv run pip install certifi

ARG STAGE

RUN sh -c 'echo "STAGE=$STAGE" > .env'
RUN sh -c 'echo "PYTHONPATH=." >> .env'
RUN chmod +x ./scripts/run.sh
RUN chmod +x ./scripts/run-worker.sh

CMD ["./scripts/run.sh"]

EX. nginx 이미지를 생성하는 예제

# Dockerfile
FROM ubuntu:22.04
MAINTAINER your-name <your-email@example.com>
LABEL purpose=Web Server

# nginx 패키지 설치
RUN apt-get update && apt-get install -y nginx

# nginx 설정 파일 복사
COPY nginx.conf /etc/nginx/nginx.conf

# Nginx 실행
CMD ["nginx", "-g", "daemon off;"]

nginx.conf

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    gzip  on;
    gzip_disable "msie6";

    include /etc/nginx/conf.d/*.conf;
}
  1. 이미지 생성

현재 디렉터리에서 Dockerfile을 기반으로 my-nginx:latest라는 이름의 Docker 이미지를 생성하는 예제임

# 안될 때 사용
docker buildx build -t my-nginx:latest .
# 정상 docker 이미지 생성 명령어
docker build -t my-nginx:latest .
  1. Container로 실행

Docker 이미지는 Docker CLI를 사용하여 컨테이너로 실행할 수 있음
my-nginx:latest이미지를 기반으로 컨테이너를 실행하고, 80번 포트를 호스트 머신의 80번 포트로 매핑하는 예제

docker run -d -p 80:80 my-nginx:latest
  1. Container 종료 방법
docker stop my-nginx

참고
생성한 Docker image는 Docker Registry라는 저장공간에 저장됨


Docker Compose

Docker Compose는 여러 컨테이너를 한 번에 적어서 설정할 수 있음. 즉 무슨 이미지를 쓸 지, 어떤 포트를 사용할 지, 환경 변수는 뭐가 필요한지 등을 적어줌 -> 여러 컨테이너를 한 번에 쉽게 설정하기 위함

앱을 개발할 때, 앱을 따로 떼어 놓고 실행하고 테스트할 수 있는 환경이 필요함 -> Docker Compose 사용
Compose 파일은 앱이 필요로 하는 모든 서비스들 (데이터 베이스, 큐, 캐시, 웹 API 등)을 정리해주고 docker compose up 명령어로 모든 걸 시작할 수 있음

EX. 자동화된 테스트 실행하기

# 테스트 환경을 만듦
docker compose up -d
# 테스트를 실행
./run_tests
# 환경 없애기
docker compose down

EX. Docker Compose 실행하기

# 1. 각 애플리케이션의 Dockerfile 작성
# 2. docker-compose.yaml 파일 작성
# 3. docker compose up으로 실행하기

docker-compose.yaml 파일 예시

services:
  web:
    build:
      context: .    # Dockerfile 의 위치
      dockerfile: Dockerfile    # Dockerfile 파일명
    container_name: testapp_web_1    # 생략하는 경우 
    # 자동으로 부여 docker run 의 --name 옵션과 동일
    ports: "8080:8080"  # docker run 의 -p 옵션과 동일
    expose: "8080"    # 호스트머신과 연결이 아니라 
    # 링크로 연결된 서비스 간 통신이 필요할 때 사용
    networks: testnetwork    # networks 를 최상위에 정의한다면 해당 이름을 사용
    # docker run의 --net 옵션과 동일
    volumes: .:/var/lib/nginx/html    # docker run 의 -v 옵션과 동일
    environment:
      - APPENV=TEST    # docker run 의 -e옵션과 동일
    command: npm start   # docker run 의 가장 마지막
    restart: always    # docker run 의 --restart 옵션과 동일
    depends_on: db    # 이 옵션에 지정된 서비스가 시작된 이후에 `web`서비스가 실행
    links: db # Docker가 네트워크를 통해 컨테이너를 연결하도록 정의합니다. 
    # 컨테이너를 연결할 때 Docker는 환경 변수를 만들고 
    # 컨테이너를 알려진 호스트 목록에 추가하여 서로를 검색할 수 있도록 합니다.
    deploy:    # 서비스의 복제본 개수 등 지정
      replicas: 3
      mode: replicated


Dockerfile -> docker-compose.yaml 플로우

Dockerfile
주로 사용하는 프로그래밍 언어, 프레임워크, 필요한 라이브러리, 실행 파일 등을 정의합니다.

# 보통 경량화를 중요시 한다면 alpine OS를 많이 사용함
FROM eclipse-temurin:21-jre-alpine

WORKDIR /app

COPY build/libs/spring-boot-0.0.1-SNAPSHOT.jar /app

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "app/spring-boot-0.0.1-SNAPSHOT.jar"]

docker-compose.yaml
애플리케이션을 구성하는 여러 서비스를 정의하고, 컨테이너 간의 관계를 설정합니다.

version: "3"
services:
  mysql:
    image: mysql:latest
    ports:
      - 23306:3306
    environment:
      - MYSQL_DATABASE=test
      - MYSQL_ROOT_PASSWORD=password
  redis:
    image: redis:latest
    ports:
      - 26379:6379
  nginx:
    image: nginx:latest
    ports:
      - 80:80
    depends_on:
      - redis
      - mysql

Docker

컨테이너의 집합

간단히 말해서
Dockerfile은 붕어빵 기계 설계도
Image는 설계도를 통해 만들어진 붕어빵 기계
Container는 붕어빵 기계를 통해 만들어진 실제 붕어빵 (프로그램)

인 것이다.

# python 이미지의 상태를 가져와 줘
docker ps | grep python 

Flask 실습

Dockerfile

# Python 3.8을 쓸건데, 가장 가벼운 이미지로 골라줘,
FROM python:3.8-slim


# Copy 내_실제_파일 컨테이너에_들어갈_파일
COPY app.py /app.py

# Flask 설치해야 함
RUN pip install flask


# RUN과 CMD의 차이
# RUN은 그냥 돌리는 거고,
# CMD는 형식이 정해져 있을 때
CMD ["python", "/app.py"]

app.py

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, Docker World!'

# port번호를 명시해주니 제대로 실행이 되었음
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5002)

Docker 이미지 빌드 및 실행

# 앞쪽 포트 번호 (5002): **호스트(로컬 머신)**의 포트 번호입니다. 브라우저에서 접근하거나 클라이언트가 요청할 때 사용하는 포트입니다.
# 뒤쪽 포트 번호 (5002): 컨테이너 내부에서 애플리케이션이 실제로 바인딩된 포트 번호입니다. -> __main__의 포트 번호와 반드시 일치해야 함
docker build -t flask-app .
docker run -d -p 5002:5002 flask-app

ex.

# 외부에서는 localhost:8080으로 접근하지만, 컨테이너 내부에서는 Flask가 5002 포트를 사용합니다.
docker run -d -p 8080:5002 flask-app

Docker 로깅

docker stats

디스크 사용량 확인 명령어

df -h

디렉터리 별 사용 공간 확인 명령어

du -sh

특정 컨테이너의 로그 보기

docker run --name logs-test --rm -d ubuntu:22.04 /bin/bash -c 'while true; do date; sleep 1; done'

# logs-test 컨테이너의 로그를 전체 출력하기
docker logs logs-test

# logs-test 컨테이너의 로그를 tailing하기
docker logs -f logs-test

# 마지막 10줄부터 로그를 계속 보기
docker logs -f --tail 10 logs-test

흠 근데 너무 복잡하다 지피티에게 물어보니

아래 코드가 제일 간단하다고 함

docker exec -it <컨테이너 이름> sh

AWS 연결

  • 주의 사항 :
    반드시 Pem키를 text변환한 전체를 actions setting에 넣어야 함!! === 이런 거 다 들어가야 함!

Docker Volume을 사용하는 이유

: 데이터를 남아있게 하기 위해서 임
: 코드와 데이터를 따로 두려고 (볼륨을 쓰면 코드를 바꿔도 데이터는 그대로 유지할 수 있어서, 개발이나 운영할 때 편리함)

tmpfs mount
컴퓨터 메모리를 사용해서 일시적인 데이터를 저장하는 방법. 컨테이너 안에서 잠깐 필요한 데이터를 다룰 때 유용

  • 일시적인 데이터 저장 : 컨테이너가 임시 데이터를 만들 때, 이를 영구적으로 저장하지 않고 메모리에만 잠시 두고 싶을 때 사용
  • 컴퓨터의 파일 시스템 사용 안함 : tmpfs 마운트는 컴퓨터의 일반 파일 시스템 대신 메모리를 사용해서 데이터를 저장함

바인드 마운트
바인드 마운트는 컴퓨터의 특정 폴더나 파일을 Docker 컨테이너 안에서 직접 쓸 수 있게 해주는 거이. 볼륨보다 기능이 좀 덜하지만, 특정 상황(실시간 코드 변경 확인)에서 유용함
사용방법 : 컴퓨터에서 어떤 폴더나 파일을 골라서 Docker 컨테이너에 "붙여 넣는" 것과 비슷함. 그러면 컨테이너 안에서도 그 파일이나 폴더를 마치 자기 것처럼 쓸 수 있음
어디에 있는 파일이나 폴더를 사용함? 바인드 마운트는 컴퓨터 안의 정확한 위치(절대 경로)에 있는 파일이나 폴더를 사용함 때문에 컨테이너가 어디에 있든, 그 파일이나 폴더를 똑같이 사용할 수 있음
-> 바인드 마운트를 사용하면 컨테이너에서 컴퓨터의 특정 파일이나 폴더를 쉽게 접근하고 사용할 수 있음. 이런 방식은 특정 개발 작업이나 데이터를 다룰 때 도움이 될 수 있음


Plus

  • 코드를 올리면 CI/CD가 사용자에게 가는 것
    (프레임을 만들면서 검증, 배포를 하는 것)
    CI는 개발 CD 계속하는 것

  • ECR에 이미지를 올림. 컨테이너를 띄워서
    로드 밸런싱 헬름

80 = http
443 = https
22 = SSH
  • 컨테이너를 종료하고 이미지를 종료해야 함

0개의 댓글