도커 개발자 커뮤니티 데이 코리아 1회
실습에 사용된 코드:
Dockerfile
Dockerfile은 컨테이너 이미지를 빌드하는 명세서로, 컨테이너화된 애플리케이션을 정의하는 설정파일입니다. 컨테이너 이미지를 만들기 위해 다양한 명령어(Instructions)를 사용합니다.
대표적인 명령어(Instructions)
명령어 | 설명 |
FROM | 베이스 이미지 지정 |
WORKDIR | 작업 디렉터리 설정 |
COPY | 로컬 파일을 컨테이너로 복사 |
RUN | 컨테이너 빌드 중 실행할 명령어 지정 |
ENV | 환경 변수 설정 |
ENTRYPOINT | 컨테이너 실행 시 시작할 명령 설정 |
Dockerfile을 사용하면 컨테이너 이미지를 일관성있게 관리하고, 자동화된 배포가 가능합니다. 하지만 작성 및 유지보수가 어렵다는 문제가 있기 때문에 이를 해결하기 위한 기술이 docker init 입니다.
Dockerfile을 자동으로 생성해주는 Docker init
docker init 이란?
•
애플리케이션 코드를 분석하여 Best Practice 기반의 Dockerfile을 자동 생성하는 명령어
•
docker init 실행 후 생성된 Dockerfile을 커스터마이징 가능
•
단점: 멀티 프로젝트 인식 불가
실습: docker init 사용하기
이번 실습에는 연사자의 Github에서 제공하는 샘플 코드를 사용합니다.
# monolith 프로젝트 디렉토리로 이동
cd ~/container-orchestration-sample-main/monolith
# docker init 실행
docker init
Bash
복사
docker init을 실행하면 .NET을 감지하고 자동으로 추천해줍니다. 메인 프로젝트(eShopLite.Store)를 선택 후, 설정 값을 지정하면 자동으로 Dockerfile이 생성됩니다.
설정 항목 | 값 |
.NET 버전 | 9.0 |
Port | 8080 |
자동 생성된 Dockerfile을 커스터마이징 해봅시다. 이번 실습에서 사용자 권한 설정과, 빈 데이터 베이스 파일 생성 부분을 추가해줍니다.
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build
COPY . /source
WORKDIR /source/src/eShopLite.Store
ARG TARGETARCH
RUN --mount=type=cache,id=nuget,target=/root/.nuget/packages \
dotnet publish -a ${TARGETARCH/amd64/x64} --use-current-runtime --self-contained false -o /app
FROM mcr.microsoft.com/dotnet/aspnet:9.0-alpine AS final
WORKDIR /app
COPY --from=build /app .
RUN chown $APP_UID /app # 사용자 권한 설정
USER $APP_UID
RUN touch /app/Database.db # 빈 데이터베이스 파일 생성
ENTRYPOINT ["dotnet", "eShopLite.Store.dll"]
Bash
복사
컨테이너 이미지를 빌드해줍니다.
docker build -t eshoplite-store:latest .
docker images
Bash
복사
컨테이너 이미지는 기본적으로 실행하는 컴퓨터의 아키텍처를 따르기 때문에, 배포 환경과 다를 경우 명시적으로 아키텍처를 설정해줘야 합니다. linux/amd64로 지정해보겠습니다.
docker build --platform=linux/amd64 --build-arg TARGET=amd64 -t eshoplite-stre:latest .
Bash
복사
컨테이너를 실행합니다.
docker run -d -p 8080:8080 --name store eshoplite-store:latest
Bash
복사
docker init의 장점과 한계
장점:
•
Dockerfile을 자동 생성하여 초보자도 쉽게 활용 가능
•
Best Practice 기반으로 최적화된 Dockerfile 제공
•
코드를 분석하여 적절한 환경 추천
단점:
•
멀티 프로젝트 인식 불가 (프로젝트가 복잡할 경우 수동 조정 필요)
•
자동 생성된 Dockerfile이 최적이 아닐 수도 있음 (커스터마이징 필요)
Dockerfile 없이 컨테이너 이미지 빌드하기
이번에는 Dockerfile을 직접 작성하지 않고도 컨테이너 이미지를 빌드하는 방법에 대해 소개합니다. 여러가지 방법들이 있지만 Java 애플리케이션의 Jib 패키지와 .NET의 dotnet publish를 이용하여 이미지를 빌드하는 방법에 대해 다룹니다.
실습 애플리케이션을 실행하기 위해서 3개 프로젝트를 실행해야 합니다.
프로젝트 명 | 빌드 방식 |
eshoplite-product | Dockerfile 직접 사용 |
eshoplite-weatherApi | Jib을 활용한 컨테이너 이미지 빌드 |
eshoplite-webApp | .NET dotnet pulbish 사용하여 이미지 빌드 |
•
프로젝트 경로: ~/container-orchestration-sample/msa
Dockerfile 빌드 (eshoplite-product)
dockerfile을 사용하여 컨테이너를 실행합니다.
docker build -f Dockerfile.product --platform=linux/amd64 --build-arg TARGETARCH=amd64 -t eshoplite-product:latest .
Bash
복사
docker run -d -p 5051:8080 --name product eshoplite-product:latest
Bash
복사
Java 애플리케이션 - Jib 패키지 활용 (eshoplite-weatherApi)
Jib란?
•
Google에서 제공하는 Maven/Gradle 플러그인으로 Dockerfile 없이 컨테이너 이미지를 직접 빌드할 수 있는 도구
•
제한: RUN 지시자를 사용할 수 없어, 컨테이너 내부에서 추가적인 명령 실행이 제한됨
•
./gradlew jib 또는 ./mvnw compile jib:build 실행
실습: Jib을 활용한 컨테이너 이미지 빌드
Spring Boot 애플리케이션을 Jib을 활용해 Dockerfile 없이 컨테이너 이미지로 빌드하고 실행하는 방법을 실습해봅니다.
•
프로젝트 경로: ~/container-orchestration-sample/msa
•
Jib을 사용하기 위해 pom.xml에 Maven 플러그인 추가
•
아래 pom.xml 파일을 보면 jib-maven-plugin을 추가하여 빌드하도록 설정
pom.xml (Jib플러그인 추가)
pom.xml에서 jib-maven-plugin을 사용해 컨테이너 이미지를 빌드하도록 설정합니다.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.devkimchi.eshop.lite</groupId>
<artifactId>weatherapi</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>weatherapi</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId> <!-- Jib 플러그인 -->
<version>3.4.4</version>
<configuration>
<from>
<image>mcr.microsoft.com/openjdk/jdk:17-ubuntu</image> <!-- JDK 17 기반 이미지 -->
<!-- <image>eclipse-temurin:17-jre-alpine</image> -->
</from>
<to>
<image>eshoplite-weather</image> <!-- 컨테이너 이미지 이름 -->
<tags>
<tag>latest</tag>
</tags>
</to>
<container>
<jvmFlags>
<jvmFlag>-Djava.security.egd=file:/dev/./urandom</jvmFlag>
<jvmFlag>-Xms512m</jvmFlag>
</jvmFlags>
<mainClass>com.devkimchi.eshop.lite.weatherapi.SpringMavenApplication</mainClass>
<ports>
<port>5050</port>
</ports>
</container>
<extraDirectories>
<paths>
<path>
<from>../../../agents</from>
<into>/agents</into>
</path>
</paths>
</extraDirectories>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
XML
복사
항목 | 설명 |
from.image | |
to.image | 빌드된 컨테이너 이미지를 eshoplite-weather 라는 이름으로 생성 |
mainClass | 실행할 메인 클래스 지정 |
ports | 컨테이너가 사용하는 포트(5050)지정 |
Jib을 이용해 컨테이너 이비지를 빌드 및 실행하기 위해 아래 명령을 실행합니다.
./mvnw compile jib:build
docker run -d -p 5050:5050 --name weather eshoplite-weather:latest
YAML
복사
(선택사항) 연사자께서는 컨테이너 이미지를 Docker Hub에 푸시하는 형태로 진행을 하였습니다.
# 도커 허브 계정으로 수정 후 실행
REGISTRY=<YOUR_DOCKERHUB_USERNAME>
./src/eShopLite.WeatherApi/mvnw clean package \
-f ./src/eShopLite.WeatherApi/pom.xml \
-Dimage="$REGISTRY/eshoplite-weather:latest"
Bash
복사
docker pull "$REGISTRY/eshoplite-weather:latest"
Bash
복사
docker tag "$REGISTRY/eshoplite-weather:latest" eshoplite-weather:latest
Bash
복사
docker run -d -p 5050:5050 --name weather "eshoplite-weather:latest"
Bash
복사
.NET - dotnet publish (eshoplite-webstore)
컨테이너 오케스트레이션이 필요하다
컨테이너는 기본적으로 독립적인 환경에서 실행되기 때문에, 서로 직접 통신할 수 없습니다. 이를 해결하기 위해서 컨테이너 오케스트레이션을 통해 네트워크를 구성해야 합니다.
Docker 네트워크 사용
Docker 네트워크를 활용하면 동일 네트워크에 속한 컨테이너들이 서로 통신할 수 있도록 설정할 수있습니다. 즉, 각 컨테이너에 개별 IP 주소를 부여하지 않고도, 컨테이너 이름 또는 별칭을 통해 다른 컨테이너에 접근 가능합니다.
실습:
먼저 컨테이너 간 통신을 위한 네트워크(eshoplite)를 생성합니다.
docker network create eshoplite
docker inspect eshoplite # 네트워크 설정 확인
Bash
복사
네트워크가 생성된 후, 컨테이너 실행 시 해당 네트워크를 지정하여 컨테이너들이 서로 통신할 수 있도록 설정합니다.
docker run -d -p 5001:8080 --network eshoplite --network-alias webstore --name websotre eshoplite-webstore:latest
docker run -d -p 5050:5050 --network eshoplite --network-alias weather --name weather eshoplite-weather:latest
docker run -d -p 5051:8080 --network eshoplite --network-alias product --name product eshoplite-product:latest
Bash
복사
항목 | 설명 |
--network | 네트워크 지정 |
--network-alias <별칭> | 컨테이너 네트워크 내에서 사용할 별칭 부여 |
컨테이너들이 네트워크에 정상적으로 연결되어 있으며, 이제 컨테이너 간 통신이 가능해집니다.
네트워크에 지정된 컨테이너가 없는 상태
지정된 컨테이너가 설정된 상태
Docker Compose 사용
Docker Compose는 여러 개의 컨테이너를 한 번에 실행하고 관리할 수 있는 도구입니다. docker run 명령을 여러 번 입력하는 대신, YAML파일을 이용해 컨테이너 설정을 자동화할 수 있습니다.
실습:
아래와 같이 compose.yml 파일을 작성하여, 여러 컨테이너를 동시에 실행할 수 있도록 설정합니다.
name: eShopLite
services:
product:
container_name: product
image: eshoplite-product:latest
ports:
- 5051:8080
weather:
container_name: weather
image: eshoplite-weather:latest
ports:
- 5050:5050
webstore:
container_name: webstore
image: eshoplite-webstore:latest
ports:
- 5001:8080
depends_on:
- product
- weather
Bash
복사
항목 | 설명 |
services | 실행할 컨테이너 목록 |
container_name | 컨테이너 이름 지정 |
image | 실행할 Docker 이미지 |
ports | 컨테이너와 호스트 간 포트 매핑 |
depends_on | 다른 컨테이너가 먼저 실행되도록 설정 |
networks | 네트워크에 컨테이너를 연결 |
networks.eshoplite | eshoplite 네트워크를 생성하고 컨테이너들이 이 네트워크를 사용하도록 설정 |
아래 명령어를 실행하면 모든 컨테이너가 자동으로 네트워크에 연결된 상태에서 실행됩니다.
docker-compose up -d
Bash
복사
모든 컨테이너가 네트워크에 정상적으로 연결된 것을 확인할 수 있습니다.
방식 | 특징 | 사용 용도 |
Docker 네트워크 | 개별 컨테이너 실행 시 --network 옵션을 사용하여 연결 | 컨테이너 수가 적고, 개별적으로 실행할 경우 적합 |
Docker Compose | 여러 컨테이너를 docker-compose.yml 파일로 관리 | 컨테이너 수가 많고, 여러 서비스를 한 번에 실행해야 할 경우 적합 |
마무리 및 느낀점
이번 커뮤니티를 통해 Dockerfile 작성, 컨테이너 빌드, 그리고 컨테이너 간 통신 과정에 대해 전반적인 흐름을 파악할 수 있었습니다. 특히, Dockerfile 없이도 컨테이너를 빌드할 수 있는 방법과 컨테이너 간 네트워크 설정에 대한 개념을 정리할 수 있어 유익한 시간이었습니다.
배운 점 요약
커뮤니티를 통해 알게 된 점: docker init
이번 커뮤니티를 통해 docker init 명령어를 사용하면 보다 쉽게 Dockerfile을 작성할 수 있다는 점을 알게되었습니다. 처음 Dockerfile 작성할 때 시행착오를 겪었던 기억이 떠오르네요, 만약 이 기능을 진작알았다면 더 수월하게 작성할 수 있었을텐데 말이죠. 이제라도 알게되어 다행이고, 앞으로 적극적으로 활용하면 좋을듯 합니다. (이래서 커뮤니티를 다니면서 배우나 봅니다.
)
녹화 제공
보통 커뮤니티에서 녹화를 제공하지 않거나, 제공하더라도 업로드까지 시간이 오래 걸리는 경우가 많습니다. 하지만 일주일도 안되어 바로 업로드가 되어 복습할 수 있었던 점이 좋았습니다. ⇒ 놓쳤던 부분을 다시 확인할 수 있어서 학습 효과가 더욱 극대화!
추가 학습 필요성
Dockerfile을 자동 생성하고, 컨테이너 이미지를 빌드하는 과정을 경험했지만, Dockerfile이 실제로 어떻게 이미지를 빌드하는지 동작 원리에 대한 추가 학습이 필요하다고 느꼈습니다.
•
Dockerfile의 빌드 단계 및 이미지 최적화 방법
•
Docker의 레이어 캐싱과 빌드 성능 최적화 방법
•
멀티 스테이지 빌드 활용법
Related Posts
Search