AWS/Docker+CICD

Dockerfile과 Docker Compose 를 사용해서 나만의 앱을 여러 개 실행

sehunbang 2024. 4. 4. 21:34

목표

  • Dockerfile 을 활용하여 나만의 이미지를 만들 수 있습니다.
  • Docker Compose 를 활용하여 여러 개의 컨테이너를 관리할 수 있습니다.
  • Docker 컨테이너를 모니터링하고 로깅을 확인할 수 있습니다.

 

01. Dockerfile로 나만의 Docker Image를 만들어요

 

 

Dockerfile 이란?

  • Dockerfile이 뭐예요?
    • Dockerfile은 컴퓨터에서 돌아가는 앱을 만들기 위한 레시피 같은 거예요. 이 레시피대로 하면 Docker 이미지라는 걸 만들 수 있어요. Docker 이미지는 앱을 실행하는 데 필요한 모든 것을 담고 있죠.
  • Dockerfile 사용하는 이유는?
    • 앱을 컨테이너로 만들 때 이미지를 만드는 용도로 Dockerfile을 써요. 이렇게 하면 앱이 필요로 하는 모든 것을 한 곳에 담을 수 있어요.
    • 누구나 Dockerfile을 보고 똑같은 앱 환경을 쉽게 만들 수 있어요. 마치 요리 레시피를 따라 하는 것처럼요.
    • Dockerfile을 작성하면, 앱을 만드는 과정을 자동화할 수 있어요. 그래서 매번 똑같은 방식으로 앱을 만들고 배포할 수 있어요.

Dockerfile 덕분에 앱을 만드는 일이 더 쉽고, 누구나 똑같은 결과를 얻을 수 있어요. 컴퓨터에서 앱을 실행하는 일이 마치 레시피대로 요리하는 것처럼 간단해져요.

# Dockerfile
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;"]

 

위 Dockerfile은 Ubuntu 최신 버전을 기반으로 Nginx를 설치하고, index.html 파일을 Nginx의 HTML 디렉토리에 복사하는 예시에요

 

Dockerfile은 다음과 같은 명령어를 포함해요. 자세한 건 뒤에서 다룰게요.

  • FROM: 베이스 이미지를 선택
  • MAINTAINER: 이미지를 만든 사람의 정보를 입력
  • RUN: 이미지에 명령을 실행하여 파일을 추가하거나 삭제
  • COPY: 파일을 이미지에 복사
  • EXPOSE: 컨테이너가 노출할 포트를 설정
  • CMD: 컨테이너가 실행될 때 실행할 명령을 설정

Docker 이미지를 생성하려면 Docker CLI를 사용하여 다음과 같은 명령을 실행해요.

 

docker buildx build -t my-nginx:latest .

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

 

 

이렇게 생성된 Docker 이미지는 Docker CLI를 사용하여 컨테이너로 실행할 수 있습니다. 예를 들어, 다음과 같은 명령어를 사용하여 컨테이너를 실행할 수 있어요.

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

 

 

위 명령어는 my-nginx:latest 이미지를 기반으로 컨테이너를 실행하고, 80번 포트를 호스트 머신의 80번 포트로 맵핑하는 예제에요.

 

이렇게 생성된 컨테이너는 Docker CLI를 사용하여 종료하거나 업데이트할 수 있습니다. 예를 들어, 다음과 같은 명령어를 사용하여 컨테이너를 종료할 수 있어요.

 

docker stop my-nginx

위 명령어는 my-nginx라는 이름의 컨테이너를 종료하는 예제에요.

 

 

 

이렇게 생성된 Docker 이미지는 Docker 레지스트리를 사용하여 다른 사용자와 공유할 수 있어요. Docker 레지스트리를 사용하면 Docker 이미지를 저장하고 공유할 수 있고, 다른 사용자가 이미지를 다운로드하여 사용할 수 있어요.

 

 

 

  • FROM: 베이스 이미지를 지정
    • ex) FROM ubuntu:22.04
  • MAINTAINER: Dockerfile을 작성한 사람의 정보를 입력
    • ex) MAINTAINER naebaecaem <nbcamp@spartacoding.co>
  • LABEL: 이미지에 메타데이터를 추가
    • ex) LABEL purpose='nginx test'
  • RUN: 이미지를 생성하는 동안 실행할 명령어를 입력
    • 사용자를 지정하지 않은 상태라면, root 로 실행
    • ex) RUN apt update && apt upgrade -y && apt autoremove && apt autoclean
    • ex) RUN apt install openjdk-21-jdk
  • CMD: 컨테이너를 생성할 때, 실행할 명령어를 입력
    • 컨테이너를 생성할 때만 실행
    • 추가적인 명령어에 따라 설정한 해당 명령어 수정 가능
    • ex) CMD ["nginx", "-g", "daemon off;"]
  • ENTRYPOINT: 컨테이너 시작할 때, 실행할 명령어를 입력
    • 컨테이너를 시작할 때마다 실행
    • 추가적인 명령어 존재 여부와 상관 없이 무조건 실행
    • ex) ENTRYPOINT ["npm", "start"]
  • ENV: 환경 변수를 설정
    • 이미지 안에 각종 환경 변수를 지정
    • ex) ENV STAGE staging
    • ex) ENV JAVA_HOME /usr/lib/jvm/java-8-oracle
  • WORKDIR: 작업 디렉터리를 지정
    • ex) WORKDIR /app
  • COPY: 파일을 복사
    • 호스트의 파일이나 디렉토리를 이미지 안에 복사
    • Docker Context, 즉, 빌드 작업 디렉토리 내 파일만 복사 가능
    • ex) COPY index.html /usr/share/nginx/html
  • USER: 사용자를 설정
    • Container의 기본 사용자는 root 에요. root 권한이 필요 없는 application이라면 다른 사용자로 변경하여 사용해야 해요.
    • RUN ["useradd", "user"] USER user RUN ["/bin/bash, "-c", "ls"]
  • EXPOSE: 컨테이너에서 노출할 포트를 지정
    • ex) EXPOSE 80
    • ex) EXPOSE 443

 

Docker파일 예제

 

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