Gom3rye

Dockerfile 본문

현대 오토에버 클라우드 스쿨

Dockerfile

Gom3rye 2025. 6. 19. 17:31
728x90

IaC

코드형 인프라

  • 수동 프로세스가 아닌 코드를 통해 인프라를 구축하고 관리하고 프로비저닝 하는 것
  • 인프라 사양을 담은 구성 파일이 생성되므로 구성을 편집하고 배포하기가 쉬워지고 동일한 환경을 프로비저닝 하도록 보장한다.
  • 구성 사양을 코드화하고 문서화함으로써 구성 변경 사항을 문서화하지 않고 임시로 변경하는 일을 막을 수 있다.
  • 버전 제어는 IaC의 중요한 부분으로 다른 소프트웨어 소스 코드 파일과 마찬가지로 구성 파일도 소스 제어가 필요하다.
  • 코드로 인프라를 배포한다는 것은 인프라를 모듈식 구성 요소로 분할하고 자동화를 통해 다양한 방식으로 결합을 할 수 있다는 의미이다.
  • IaC로 인프라 프로비저닝(구성, 배포)을 자동화하면 애플리케이션을 개발하거나 배포할 때마다 개발자가 직접 서버, 운영체제, 스토리지, 기타 인프라 구성 요소를 수동으로 프로비저닝하고 관리할 필요가 없어지는데 인프라를 코드화하여 템플릿을 만들고 프로비저닝 할 때 이 템플릿을 사용하면 된다.
  • Docker, Kubernetes(애플리케이션을 배포할 때), Ansible(환경 만들 때) 등이 IaC를 구현하기 위한 도구들이다.

Dockerfile

Dockerfile은 DockerImage를 생성하기 위한 스크립트

여러 명령어를 토대로 Dockerfile을 작성한 후 빌드하면 Docker는 Dockerfile에 나열된 명령문을 차례대로 수행하여 DockerImage를 생성한다.

  • 장점
    • 이미지가 어떻게 만들어졌는지 기록할 수 있다.
    • 배포에 용이하다.
    • 컨테이너가 특정 행동을 수행하도록 할 수 있다.
  • 최적의 Dockerfile
    • 경량의 컨테이너 서비스를 제공: 빠른 컨테이너 배포를 위해 최소한의 설정과 구성을 권장한다.
    • Dockerfile에 담기는 레이어 최소화
      • Dockerfile의 명령어 수와 Docker 이미지 레이어 수는 동일하므로 레이어 수가 많을 수록 이미지를 생성하는 빌드 시간은 길어질 것이고 파일 용량도 커지게 되기 때문에 레이어 수를 줄일 수 있도록 Dockerfile 명령어 사용 방법을 정확히 알고 작성해야 한다.
    • 되도록이면 하나의 애플리케이션은 하나의 컨테이너로
      • 하나의 컨테이너에 2개 이상의 애플리케이션을 설정하게 되면 애플리케이션의 결합성이 높고 확장성을 저해한다.
      • 하나의 컨테이너에 하나의 애플리케이션이 동작하도록 하면 컨테이너 간에 독립성을 보장함과 동시에 애플리케이션 버전 관리, 소스 코드 모듈화 등에서 이점이 있으므로 모놀리식 구성 보다는 decouple application(느슨한 결합) 설계 또는 마이크로 서비스 지향적 설계를 고려해야 한다.
      • IaC 환경 개발은 디렉토리 단위: 이미지 빌드와 상관없는 파일이 포함되지 않도록 별도의 디렉토리를 생성한다.
      • 서버리스 환경으로 개발한다.
      • 캐시 기능을 활용한다.
        • Dockerfile을 통해 이미지를 빌드하면 자동으로 각 명령어 단위로 캐싱하므로 동일한 명령의 실행은 캐싱을 통해 재사용되서 빌드 속도를 빠르게 한다.
        • 순서가 중요! Docker의 이미지 레이어가 특정한 순서대로만 배치된다고 가정하기 때문에 중간에 있는 레이어가 변경되면 변경된 레이어보다 위에 오는 레이어는 재사용 할 수 없다.
        • 도커는 각 Dockerfile 명령어(인스트럭션)마다 해당 명령어와 그에 영향을 주는 파일들의 내용을 해시로 계산해 캐시를 확인한다.
        • 만약 이전에 같은 해시값(즉, 같은 내용과 명령어)이 이미 빌드되어 캐시가 존재하면 그 레이어를 재사용한다.
        • 반대로 해시값이 없으면 캐시 미스가 발생하여 해당 명령어를 다시 실행하고, 그 이후 인스트럭션들도 새로 빌드하게 된다.
        • 따라서 이 때문에 Dockerfile에서 변경된 부분 이후의 모든 단계가 다시 빌드되는 것이고, 캐시 활용을 위해서는 Dockerfile 작성 시 명령어 순서와 복사 대상 파일을 신중히 관리하는 게 중요하다.
          • 변경이 될 가능성이 높은 것을 맨 마지막에 쓰자. 잘 변경이 안 될 것들을 앞에 쓰고

Dockerfile 작성 명령어

FROM

  • 필수 항목
  • Image의 바탕이 될 Base Image를 지정한다.
  • hub.docker.com 에서 제공하는 공식 이미지를 권장한다.
  • 이미지를 선택할 때 작은 크기의 이미지(slim)와 리눅스 배포판인 알파인(Alpine) 이미지를 권장하지만 모든 애플리케이션이 동일하진 않는다.
  • 태그를 지정하지 않으면 latest
  • 작성 예
    • FROM ubuntu:20.04
    • FROM python:3.9-slim-buste

MAINTAINER

이미지를 빌드한 작성자 이름과 이메일을 작성한다.

LABEL

이미지 작성 목적

  • 버전, 타이틀, 설명, 라이선스 정보를 작성한다.
  • 여러 개 작성 가능하다.
    • ex. LABEL version=’1.0’ LABEL description = ‘web service application’

RUN

Dockerfile 내에서 이미지 빌드 중 명령어를 실행할 때 사용되며, 실행 결과는 새로운 이미지 레이어로 생성된다. (명령어 하나 당 이미지 하나 생기기 때문에 최대한 명령어 연결해서 쓰기)

  • 설정된 기본 이미지에 패키지 없데이트, 각종 패키지 설치, 명령 실행 등을 작성한다.
  • 여러 개 작성 가능하다.
  • 권장 사항
    • 다단계 빌드 사용을 권장 - 각 이미지 별로 개별 Dockerfile로 빌드
    • RUN 명령어의 개별 명령 수를 최소화하기 위해 여러 설치 명령을 연결하면 이미지의 레이어 수는 감소한다.
    • autoremove, autoclean, rm -rf/var/lib/apt/lists/* 을 사용하면 저장되어 있는 apt 캐시가 삭제되므로 이미지 크기가 감소한다.
  • 사용 방식
    • exec 방식
    RUN ["/bin/bash", "-c", "apt update"]
    RUN ["/bin/bash", "-c", "apt install -y nginx git vim curl"] 
    
    → -y 안 넣으면 에러난다. interaction을 요구하기 때문에 사람의 개입이 필요해지기 때문이다. (IaC는 사람의 개입 없이 하려고 하는데)
    • shell 방식
    RUN apt update && apt install -y nginx \\
    git \\
    vim \\
    curl \\
    apt clean -y && apt autoremove -y && rm -rfv /tmp/* /var/lib/apt/lists/* /var/tmp/*
    

CMD

생성된 이미지를 컨테이너로 실행할 때 실행되는 명령

  • ENTRYPOINT 명령문으로 지정된 커맨드에 넘길 파라미터를 지정할 때 사용한다.
  • 여러 개의 CMD를 작성하더라도 마지막 하나만 처리한다.
  • 이미지의 컨테이너 실행 시 애플리케이션 데몬이 실행되도록 하는 경우에 사용한다.
CMD["/usr/sbin/apachectl", "-D", "FOREGROUND"]
CMD apachectl -D FOREGROUND

ENTRYPOINT

  • CMD와 마찬가지로 생성된 이미지가 컨테이너로 실행될 때 사용되지만 컨테이너가 실행될 때 명령어 및 인자 값을 전달해서 실행한다는 점이 다르다.
  • 여러 개의 CMD를 사용하는 경우 ENTRYPOINT 명령문과 같이 사용한다.
  • ENTRYPOINT는 커맨드를 지정하고 CMD는 기본 명령을 지정하면 탄력적으로 이미지를 실행할 수 있다.
  • python 명령으로 runapp.py 파일을 실행
ENTRYPOINT ["python"]
CMD ["runapp.py"]
  • 스크립트 파일 실행
ADD ./entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/bin/bash", "/entrypoint.sh"]
  • ENTRYPOINT는 Docker 컨테이너 실행 시 항상 수행해야 하는 명령어를 지정(웹 서버나 데이터베이스 등의 데몬 실행)하는데 이용하고 CMD는 Docker 컨테이너 실행 시 다양한 명령어를 지정하는 경우에 유용하다.

COPY

호스트 파일이나 디렉토리를 이미지 안에 복사하는 명령

  • 단순한 복사 작업만 지원한다.
  • 빌드 작업 디렉토리 외부의 파일은 COPY할 수 없다.
COPY index.html /usr/share/nginx/html
COPY ./runapp.py /
COPY ./app

ADD

호스트 환경의 파일, 디렉토리를 이미지 안에 복사 가능하고 URL에서 직접 다운로드해서 이미지에 넣을 수도 있고 압축 파일(tar, tar.gz)의 경우 압축을 풀어서 추가해준다.

(copy도 복사, add도 복사긴 한데 add가 조금 더 효율적인 경우가 많다.)

  • 빌드 작업 디렉토리의 외부의 파일은 ADD 할 수 없고 디렉토리를 추가시에는 /로 끝이다.
ADD index.html /usr/share/nginx/html
ADD <http://example.com/view/customer.tar.gz> /workspace/data/

ENV

이미지 안에 각종 환경 변수를 지정하는 경우 작성

  • 애플리케이션 사용을 쉽게 하기 위해 사전에 구성되어야 하는 환경 변수들이 있는 경우 사용한다.
  • 자바 홈 디렉토리, 특정 실행 파일의 경로를 보장하기 위해 절대 경로 지정을 위한 PATH 설정, 프로그램 버전 등을 사전에 설정한다.
  • 반복된 표현이 사용되는 경우에도 환경 변수 설정을 권장한다.
ENV JAVA_HOME /usr/lib/jvm/java-8-oracle

EXPOSE

포트포워딩

  • 컨테이너가 호스트 네트워크를 통해 들어오는 트래픽을 Listening 하는 포트와 프로토콜을 지정하기 위해 작성한다.
  • nginx나 apache는 기본 포트로 HTTP 80 그리고 HTTPS 443번 포트를 사용한다.
  • 이미지 내에 애플리케이션이 사용하는 포트를 사전에 확인하고 호스트와 연결되도록 구성하는 경우에 설정하고 docker run 사용 시 -p 옵션을 통해 포트포워딩을 해서 사용한다.
EXPOSE 80 # 또는
EXPOSE 80/tcp

VOLUME

저장소

  • 볼륨을 이미지 빌드에 따라 설정하는 경우 작성
  • 볼륨으로 지정된 컨테이너의 경로는 /var/lib/docker 로 연결된다.
VOLUME /var/log

USER

컨테이너의 기본 사용자는 root

RUN ["useradd", "adam"]
USER adam

WORKDIR

컨테이너 상에서 작업할 경로 전환을 위해 사용한다.

  • RUN, CMD, ENTRYPOINT, COPY, ADD 명령 모두 이 디렉토리에서 수행된다.
  • 지정한 경로가 없으면 자동 생성되고 컨테이너 실행 이후 컨테이너에 접속하면 지정한 경로로 연결된다.
    • docker exec -it 컨테이너이름 bash
WORKDIR /workspace

ARG

Argument

  • Docker build 시점에서 변수의 값을 전달하기 위해 --build-arg=값 을 정의해서 사용한다.
  • 비밀키, 계정 비밀번호 같은 민감한 정보들은 이미지에 직접 노출하지 않고 실행할 때 입력하게 하고자 사용한다.
ARG db_name
docker build -build-arg db_name=adam_db .
CMD db_start.sh -h 127.0.0.1 -d $(db_name)
## -> adam_db가 들어간다.

ONBUILD

처음 이미지 빌드에 포함하지만 실행되지 않고 해당 이미지가 다른 이미지의 기본 이미지로 사용되는 경우 실행될 명령을 지정할 때 작성한다.

  • 복잡한 거 만들 때 사용되므로 자주 쓸 일 없다.
  • ONBUILD 명령은 부모 Dockerfile이 자식 Dockerfile에 명령을 전달하고자 하는 경우 사용한다.
    • 1차 개발에서 환경을 만들어주고 2차 개발에서 ONBUILD에 지정된 소스를 실행한다.

STOPSIGNAL

docker stop 명령은 컨테이너에게 SIGTERM을 보내서 정지시킨다.

  • 다른 시그널을 보내고자 할 때 사용한다.
STOPSIGNAL SIGKILL

SHELL

Dockerfil 내부에서 사용할 기본 셸을 지정하는 경우 작성한다.

SHELL ["/bin/bash", "-c"]

HEALTHCHECK

컨테이너의 프로세스 상태를 체크하는 명령어

  • 하나의 명령만이 유효하다.(마지막에 작성된 체크가 유효)
  • 옵션
    • --interval=초 (기본값은 30초)
    • --timeout=초 (기본값은 30초)
    • --retries=횟수 (기본값은 3)
  • 상태 코드를 리턴한다.
    • 0: success로 컨테이너가 정상 작동한다.
    • 1: unhealthy로 컨테이너가 올바르게 작성하지 않는다.
    • 2: starting으로 예약된 코드
      • docker container inspect나 docker ps로 확인 가능하다.
    • 1분마다 cmd에 있는 명령을 실행해 3초 이상이 소요되면 한 번의 실패로 간주하고 5번의 타임아웃이 발생하면 컨테이너의 상태를 unhealty로 변경한다.
    HEALTHCHECK --interval=1m --timeout=3s --retries=5 CMD curl -f <http://localhost> || exit 1
    

작성 방법

일반적으로 FROM 명령부터 작성하는데 그 다음 명령부터는 순서가 없지만 명령 순서는 빌드 캐시의 무효화와 관련 있기 때문에 빈도 수가 적은 명령을 먼저 배치하는 것을 권장한다.

  • 기본은 운영체제부터 시작하지만 원하는 애플리케이션이 설치된 이미지가 있다면 그 이미지를 사용하는 것을 권장한다.

이미지 생성

이미지 생성 명령어

docker build [옵션] 이미지이름 [:태크] Dockerfile 파일의 디렉토리경로

  • 옵션
    • t: 태그를 지정하는 경우
      • -t 옵션은 빌드한 이미지에 이름과 태그를 붙여서 관리하기 쉽게 하는 것이므로, 꼭 붙여주는 게 좋다.
    • f: 파일 이름이 Dockerfile 이 아닌 경우 파일 이름을 설정하고자 하는 경우에 사용한다.
  • 현재 디렉토리에 존재하고 파일 이름이 Dockerfile인 경우
docker build -t 이미지이름:태그 .
  • . 대신에 git hub url 이나 압축 파일의 경로를 설정하는 것이 가능하다. (압축 파일 주면 자기가 압축을 푼다.)

ex.

index.html 파일을 welcome file로 사용하는 httpd 이미지를 생성

(되도록이면 하나의 디렉토리에서 하는게 좋다고 했으니 새 디렉토리 만들고 그 안에서 작업하자!)

  • index.html을 작성
<h1>Dockerfile</html>
  • Dockerfile 작성
FROM httpd # 베이스 이미지
COPY index.html /usr/local/apache2/htdocs/ # 명령문 
  • 빌드
docker build -t 이미지이름 도커파일의경로
docker build -t apacheex . # 현재 디렉토리에 있다는 뜻

  • 이미지 확인
docker images

컨테이너로 만들고 싶으면 run 사용, 아파치는 항상 포트포워딩 해줘야 한다.

  • 컨테이너로 생성
docker run -dit -p 8080:80 --name apacheweb apacheex
  • 확인
curl localhost:8080

Dockerfile을 사용했을 때 장점

요구 사항

  • ubuntu에 apache2 웹 서버를 이용해서 PHP 웹 페이지를 구동하라.
docker run -it --name myweb -p 8095:80 ubuntu

→ ubuntu: 운영체제 ⇒ 따라서 -dit를 넣어도 백그라운드에서 실행 x curl 확인을 하려면 원격창 하나 더 띄워서 거기서 확인해야 한다. (nginx는 원격창 하나에서 exec 명령으로 확인도 가능했던 반면)

  • 패키지 정보 업데이트
apt update
  • 아파치 웹 서버 설치 (-y 중요!)
apt install -y apache2
  • 아파치 웹 서버 구동
service apache2 start

(여기선 systemctl 명령어가 없다.)

  • 확인 (여기서만 다른 원격창에서)
    • 다른 컴퓨터에서 접속한 후 curl localhost:8095 나 브라우저에서 접속
  • welcome file(웹 사이트에 접속했을 때 기본적으로 보여지는 페이지) 이름을 변경
mv /var/www/html/index.html /var/www/html/index.html.org
  • vim 설치
apt install -y vim
  • php 설치
apt install -y php
  • php 파일 작성
vim /var/www/html/index.php
<?php
	phpinfo();
?>

  • 아파치 웹 서버 재시작
service apache2 restart

→ curl localhost:8095 만 해도 위와 같음

  • 이미지 만들기
docker commit myweb myphpapp:1.0

기본적으로 dockerfile을 쓸 수 없으면 이렇게 이미지를 만들어야 한다.

Dockerfile로 이미지 만들기

  • php 디렉토리 만들기
  • Dockerfile 만들기 : vi Dockerfile
FROM ubuntu # 베이스 이미지
MAINTAINER "kyla <gom3rye@gmail.com>"
LABEL title "IaC PHP Application"

RUN apt update
RUN apt install tzdata
RUN apt install -y php
RUN apt install -y apache2
RUN apt install -y git
RUN apt install -y curl
RUN apt install -y ssh
RUN apt install -y wget

ENV APACHE2_RUN_USER www-data
ENV APACHE2_RUN_GROUP www-data
ENV APACHE2_LOG_DIR /var/log/apache2
ENV APACHE2_WEB_DIR /var/www/html
ENV APACHE2_PID_FILE /var/run/apache2/apache2.pid

RUN echo 'Hello Docker Application' > /var/www/html/index.html
RUN echo '<?php phpinfo(); ?>' > /var/www/html/index.php

EXPOSE 80

WORKDIR /var/www/html # 뒤에 나온 디렉토리 참조
CMD ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"] # 데몬으로 실행시키기
  • 이미지 만들기
docker build -t 이름 도커파일의위치
docker build -t myphpapp:3.0 .

  • 컨테이너 생성
docker run -dit -p 8967:80 --name=phpapp myphpapp:3.0

Kafka

2011년 LinkedIn이 만든 애플리케이션

  • 파편화된 데이터 수집에 이용할 목적으로 개발되었다.
  • 소스 애플리케이션과 타깃 애플리케이션을 연결하는 파이프라인 개수가 많아지면서 소스 코드 및 버전 관리에서 이슈가 생겼고 타깃 애플리케이션에 장애를 생길 경우 그 영향이 소스 애플리케이션에 그대로 전달되었다. (직접 통신의 단점)
  • 실제 구독과 게시는 토픽 단위로, 주고 받는 데이터는 파티션 단위로

  • 속도가 중요한 애들은 스피드 레이어로 메모리를 써서 바로, 배치 레이어는 배치 데이터를 모아서 일괄 처리

리눅스 머신에 설치

  • Java 설치(Kafka는 Java로 만들어져 있다.)
    • Python, JavaScript → 줄 단위로 읽어서 해석한 후 실행, 스크립트 방식으로 실행 → Runtime이 있어야 한다.
    • Java → Byte code라는 중간 코드를 생성해서 기본적인 것들은 소유하지 않고 jre에서 받아서 사용한다. ⇒ java application은 jre가 설치되어 있어야 한다.
    • C, Go → 실행 파일을 만드는 구조로 컴파일 할 때만 c, go가 설치되어 있으면 된다.
  • JDK 설치
sudo apt-get update
sudo apt install openjdk-17-jdk
java -version
  • kafka 디렉토리 만들어주고 kafka 설치
mkdir kafka
cd kafka
wget <https://archive.apache.org/dist/kafka/3.6.0/kafka_2.13-3.6.0.tgz>
tar xvf kafka_2.13-3.6.0.tgz
ll # 확인
sudo mv kafka_2.13-3.6.0 /opt/kafka # opt는 PATH에 있어서 바로바로 실행할 수 있게끔
nano ~/.bashrc # 환경 변수에 추가
		export KAFKA_HOME=/opt/kafka
		export PATH=$PATH:$KAFKA_HOME/bin # 적고 Ctrl+o -> enter -> Ctrl+x 로 빠져나오기
source ~/.bashrc # 변경 내용 적용

# 힙 메모리 설정: 카프카는 기본적으로 1GB 이상의 메모리를 요구하고 실행할 때 메모리가 부족하면 종료된다.
nano ~/.bashrc # 힙 메모리 제한 설정해주기
		export KAFKA_HEAP_OPTS="-Xmx400m -Xms400m"
source ~/.bashrc # 변경 내용 적용

→ 이렇게 뜨면 잘 설정된 것

  • kafka 외부 접속 설정 → 이거 안 해주면 외부에서 못 들어온다.
# config 디렉토리에 있는 server.properties 파일을 수정
nano /opt/kafka/config/server.properties
		listeners=PLAINTEXT://:9092
		advertised.listeners=PLAINTEXT://10.0.2.101:9092 # ip:포트번호
		delete.topic.enable=true
		auto.create.topics.enable=true # 작성
  • 주키퍼와 카프카 실행
# 주키퍼 실행
zookeeper-server-start.sh -daemon /opt/kafka/config/zookeeper.properties
jps -vm

# 카프카 브로커 실행
kafka-server-start.sh -daemon /opt/kafka/config/server.properties
jps -m
  • 제대로 잘 켜졌는지 로그 확인
tail -f /opt/kafka/logs/server.log

728x90
반응형

'현대 오토에버 클라우드 스쿨' 카테고리의 다른 글

Git Action  (1) 2025.06.23
Dockerfile (앱 빌드, Private Registry)  (0) 2025.06.20
Volume  (2) 2025.06.18
Docker 명령어  (0) 2025.06.17
현대 오토에버 클라우드 교육 참여 소감  (0) 2025.06.17