AI 부트캠프 - Docker

Cookie Baking·2024년 12월 5일

AI 부트 캠프 TIL

목록 보기
29/42

도커 사용이유

  • CI/CD에서 지속적인 통합 과정의 테스트에서 Docker를 활용함
  • 어떤 서버에 올리더라도 같은 환경으로 구성된 컨테이너로 동작하기 때문에 표준화된 배포를 구성할 수 있음
  • 여러 애플리케이션의 독립성과 확장성이 높아짐
  • Docker가 가상화에서 사실상 표준의 위치
# docker for mac
brew install docker docker-compose

# docker version 확인
docer --version 

# 실행확인
docker info

도커 container 실행
도커의 container는 설계도 (image)를 기반으로 실행되는 실행환경을 의미함

# 도커의 image란 컨테이너의 "설계도"역할을 의미함
docker image pull nginx:1.25.3-alpine

# images 목록
docker images

docker image history nginx:1.25.3-alpine

# container 실행 명령어
docker run -d -p 8001:80 --name webserver01 nginx:1.25.3-alpine

# container 실행 확인 명령어
docker ps | grep webserver01

docker port webserver01

curl localhost:8001


# Docker 이미지 구조 확인 (json 형태로)
docker image inspect

docker image history

Docker Container 수동 생성

docker pull ubuntu:22.04
docker images

# docker create는 실제 실행하지 않고 컨테이너 생성만
docker create -ti --name ubuntu2204test ubuntu:22.04

# 모든 컨테이너가 보이는 명령어
docker ps -a
CONTAINER ID   IMAGE          COMMAND       CREATED         STATUS    PORTS     NAMES
2ccc1b2a1144   ubuntu:22.04   "/bin/bash"   4 seconds ago   Created 

# container 실행 방법 1
docker start ubuntu2204test
Ubuntu2204test
docker attach ubuntu2204test

# container 실행 방법 2
# docker run 은 create/start/attach 를 순차적으로 한 번에 실행하는 것과 같음 
docker run -ti --name=ubuntu2204test2 ubuntu:22.04 /bin/bash
root@57a1a1c759b6:/#

# 실행 중인 container를 확인하려면?
ps -ef | grep ubuntu2204test3
user   9710  7637  0 17:17 pts/4    00:00:00 docker run -ti --name=ubuntu2204test3 ubuntu:22.04 /bin/bash
user   9921  9377  0 17:17 pts/5    00:00:00 grep --color=auto ubuntu2204test3

docker run 자주 사용하는 옵션

-d : detached mode : 백그라운드 모드
-p : 호스트와 컨테이너의 포트를 연결 (포워딩)
-v : 호스트와 컨테이너의 디렉토리를 연결 (마운트)
-e : 컨테이너 내에서 사용할 환경변수 설정
-name : 컨테이너 이름 설정
-rm : 프로세스 종료 시 컨테이너 자동 삭제
-ti : -i와 -t를 동시에 사용한 것으로 터미널 입력을 위한 옵션

컨테이너 명령 테스트

cd ~
mkdir nodejsapp
cd nodejsapp
vi app.js # 테스트용 nodejs 앱
vi Dockerfile # 새로운 도커 이미지를 위한 Dockerfile
docker buildx build -t node-test:1.0 . # 1.0 태그를 추가하여 node-test라는 이미지를 빌드 
docker images | grep node-test  # 빌드 완료한 이미지 보기
docker image history node-test:1.0 # 1.0으로 태그 추가한 이미지의 Dockerfile history
docker run -itd -p 6060:6060 --name=node-test -h node-test node-test:1.0
docker ps | grep node-test
curl http://localhost:6060

실행 중인 Container에 대한 정보

# 컨테이너에서 실행 중인 프로세스 조회
docker top node-test 
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                2398                2378                0                   08:37               ?                   00:00:00            /sbin/tini -- node runapp.js
root                2421                2398                0                   08:37               ?                   00:00:00            node runapp.js

# 컨테이너에 매핑된 포트 조회
docker port node-test
8080/tcp -> 0.0.0.0:8080

# 컨테이너 리소스 통계 출력 (1회)
docker stats node-test --no-stream
CONTAINER ID   NAME        CPU %     MEM USAGE / LIMIT     MEM %     NET I/O        BLOCK I/O   PIDS
14c475f7ac09   node-test   0.01%     9.035MiB / 15.45GiB   0.06%     1.5kB / 518B   0B / 0B     11

# 컨테이너 리소스 통계 출력 (스트림)
docker stats node-test

docker logs

# 표준 출력(stdout), 표준에러(stderr) 출력
docker logs node-test 
…
 

# 로그를 계속 출력
docker logs –f node-test
…
…

# 출력된 로그는 파일로 관리되기 때문에 HostOS 의 disk 를 사용
docker info | grep -i log

컨테이너 내부 확인

# 컨테이너 내부 확인
docker inspect node-test
[
    {
        "Id": "2ccc1b2a114495e2d0b67f84e55c9c21e79c6bfff6355ae1fc2caa5225698bba",
        "Created": "2023-10-29T08:04:36.295616146Z",
        "Path": "/bin/bash",
        "Args": [],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 1814,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2023-10-29T08:05:15.974255879Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
        "Image": "sha256:e4c58958181a5925816faa528ce959e487632f4cfd192f8132f71b32df2744b4",
        "ResolvConfPath": "/var/lib/docker/containers/2ccc1b2a114495e2d0b67f84e55c9c21e79c6bfff6355ae1fc2caa5225698bba/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/2ccc1b2a114495e2d0b67f84e55c9c21e79c6bfff6355ae1fc2caa5225698bba/hostname",

docker container 정리

# 중지된 컨테이너를 포함하여 모든 컨테이너 리스트
docker container ls -a

# 태그가 붙지 않은 (dangling) 모든 이미지 삭제
docker image prune

# 남아 있는 이미지 리스트 확인 - 실행 중인 컨테이너의 이미지 등
docker image ls

# 사용하지 않는 도커 이미지, 컨테이너, 볼륨, 네트워크 등 모든 도커 리소스를 일괄적으로 삭제
docker system prune

Github에서 Github Actions란?

Github Actions는 Github에 내장된 CI/CD 도구

  • Github에 내장되어 있는 CI/CD라 github와 통합이 쉽고, CI/CD 서버가 내장되어 CI/CD 서버를 따로 구축할 필요 없으며, 일정 수준까지 가격이 무료 (500MB, 월 2000분)

Github Actions 동작 방법

  • repository의 .github/workflows 디렉터리에 필요한 Actions 파일들을 yaml 형식으로 작성
  • 반드시 .github/workflows 폴더 아래에 YAML 파일이 위치해야 함
  • 작성된 actions 파일들을 github에서 자동으로 실행

Github Actions에서 CI란

Github Actions의 CI

  • test를 통과한 코드만 develop 브랜치와 main 브랜치에 merge되도록 하여 오류를 방지하고 안정적인 코드가 배포되고 버그를 빠르게 발견
  • develop 브랜치에 merge된 경우, gradle test를 진행

예시 코드 (YAML)

# Actions 이름 github 페이지에서 볼 수 있다.
name: Run Test

# Event Trigger 특정 액션 (Push, Pull_Request)등이 명시한 Branch에서 일어나면 동작을 수행한다.
on: 
    push:
        # 배열로 여러 브랜치를 넣을 수 있다.
        branches: [ develop, feature/* ]
    # github pull request 생성시
    pull_request:
        branches: 
            - develop # -로 여러 브랜치를 명시하는 것도 가능

    # 실제 어떤 작업을 실행할지에 대한 명시
jobs:
  build:
  # 스크립트 실행 환경 (OS)
  # 배열로 선언시 개수 만큼 반복해서 실행한다. ( 예제 : 1번 실행)
    runs-on: [ ubuntu-latest ] 

    # 실제 실행 스크립트
    steps: 
      # uses는 github actions에서 제공하는 플러그인을 실행.(git checkout 실행)
      - name: checkout
        uses: actions/checkout@v4

      # with은 plugin 파라미터 입니다. (java 17버전 셋업)
      - name: java setup
        uses: actions/setup-java@v2
        with:
          distribution: 'adopt' # See 'Supported distributions' for available options
          java-version: '17'

      - name: make executable gradlew
        run: chmod +x ./gradlew

      # run은 사용자 지정 스크립트 실행
      - name: run unittest
        run: |
          ./gradlew clean test

Github Actions의 CD란?

main 브랜치에 코드가 통합된 경우 운영 환경에 빠르게 배포할 수 있게 함

예시 코드

name: 'CD'

on: 
    push:
        branches: [ main ]
jobs:
  cd:
    runs-on: [ ubuntu-latest ] 
	
    
    # main 브랜치에 merge된 경우, gradle test를 실행
    # main 브랜치의 코드 기준으로 jar 파일을 생성
    # 생성된 jar 파일을 특정 환경 (AWS, GCP 등)에 배포
    steps: 
      - name: checkout
        uses: actions/checkout@v4

      - name: java setup
        uses: actions/setup-java@v3
        with:
          distribution: 'adopt' # See 'Supported distributions' for available options
          java-version: '17'

      - name: run unittest
        run: |
          ./gradlew clean test
		  
      - name: deploy to heroku
	      uses: akhileshns/heroku-deploy@v3.12.12
		    with:
          heroku_api_key: ${{secrets.HEROKU_API_KEY}}
          heroku_app_name: "sampleapp-github-actions" #Must be unique in Heroku
          heroku_email: "nbcdocker@proton.me"


FLOW 정리

  1. 기본적인 프로젝트 파일 생성 (test 파일도 같이 위치해있으면 더 좋음)
  2. 깃허브 remote 연결
  3. 먼저 main에 push
  4. .github/workflows 디렉터리 생성
  5. run-test.yaml 파일 생성 및 CI/CD 구성 (main브랜치 이전 브랜치를 run 대상으로 설정)
  6. push 해보기 (github 액션 확인)

배포까지 하려면? (cloudtype이용)
1. github settings (내 계정) 의 Developer Settings tokens의 token 생성 (generate new token)

  1. CloudType에서 API key 설정, 깃허브 레포지포리 연결

  2. 깃허브 레포지토리에 workflows의 yml 파일에 프로젝트, 레포명 입력


자 다시 Docker

Dockerfile

Dockerfile은 컴퓨터에서 돌아가는 앱을 만들기 위한 레시피 같은 것임.
이 레시피대로하면 Docker 이미지를 만들 수 있음
Docker 이미지는 앱을 실행하는 데 필요한 모든 것을 담고 있음

왜 사용함?

  • 앱을 컨테이너로 만들 때 이미지를 만드는 용도로 Dockerfile을 사용함 -> 이렇게 하면 앱이 필요로 하는 모든 것을 한 곳에 담을 수 있음
  • 누구나 Dockerfile을 보고 똑같은 앱 환경을 쉽게 만들 수 있음
  • Dockerfile을 작성하면, 앱을 만드는 과정을 자동화할 수 있음, 즉 매번 똑같은 방식으로 앱을 만들고 배포할 수 있음

형싱은 아래와 같은데
아래 파일은 Ubuntu 최신 버전을 기반으로 Nginx를 설치하고, index.html 파일을 Nginx의 HTML 디렉터리에 복사하는 예시임

FROM ubuntu:latest
MAINTAINER Your Name <your-email@example.com>
RUN apt-get update && apt-get install -y nginx
COPY index.html /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
  • FROM : 베이스 이미지를 선택
  • MAINTAINER : 이미지를 만든 사람의 정보를 입력
  • RUN : 이미지에 명령을 실행하여 파일을 추가하거나 삭제
  • COPY : 파일을 이미지에 복사
  • EXPOSE : 컨테이너가 노출할 포트를 설정
  • CMD : 컨테이너가 실행될 때 실행할 명령을 설정

Docker 이미지를 생성하려면 Docker CLI를 사용하여 아래와 같은 명령을 실행함

docker buildx build -t my-nginx:latest .
docker build -t my-nginx:latest . # 위 명령이 실행되지 않는 경우 실행

컨테이너 실행하는 명령어

docker run -d -p 80:80 my-nginx:latest

컨테이너 종료하는 명령어

docker stop my-nginx

Docker 파일로 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"]

nginx 이미지를 생성하는 예제 (nginx:latest와 동일)

# 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;
}

Docker Compose 실행하기

  1. 각 애플리케이션의 Dockerfile 작성

  2. docker-compose-yaml 파일 작성
    내가 만든 애플리케이션을 실행하기 위해 필요한 database라든지 redis라든지 다른 서비스들을 한꺼번에 정의하는 파일을 작성

  3. docker compose up 으로 실행

  • yaml 파일은 들여쓰기가 중요한 역할을 하므로 https://www.yamllint.com/ 에서 검사를 한 후 사용하는 게 더 안전하겠음

0개의 댓글