Docker Hub 이미지와 WSL을 사용해서 나만의 이미지 만들기
윈도우즈 WSL(Windows Subsystem for Linux)를 사용해서 Docker용 베이스 이미지나 배포 이미지를 만드는 절차를 알아보겠습니다. 도커 데스크탑을 사용할 수도 있으나 리눅스 시스템에서 도커를 운영할 예정이므로 공부한다는 생각으로 조금 귀찮은 길은 선택했습니다.
- 단계: WSL 환경 준비 및 Docker 실행
- Windows의 WSL로 리눅스 사용하기 글 참고
- OCI VM(ubuntu)에 Nextcloud AIO 설치하기 글에서 “3. Docker 엔진 설치하기” 부분 참고
- WSL의 Ubuntu 프롬프트에서
docker version명령어를 실행하여 정상 작동하는지 확인합니다.
- 단계: 빌드용 폴더 및 재료 준비
- 윈도우즈 C: 드라이브는 Ubuntu “/mnt/c”에, 윈도우즈 D: 드라이브는 Ubuntu “/mnt/d”에 마운팅되어 있습니다. 윈도우즈와 Ubuntu 간에 파일의 복사/이동이 쉽도록 “/mnt/d”에 하위 디렉토리로 wsl을 생성하겠습니다. 앞으로 모든 작업은 “/mnt/d/wsl” 디렉토리에 진행합니다.
root@wsl-ubuntu:~# mkdir -p /mnt/d/wsl; cd !$ -- 베이스 이미지 저장용 디렉토리 root@wsl-ubuntu:/mnt/d/wsl# mkdir -p ./docker/base-image -- Java Application 이미지 빌드용 디렉토리 root@wsl-ubuntu:/mnt/d/wsl# mkdir -p ./docker/app-build
- eclipse-temurin:17-jre 이미지를 사용해서 베이스 이미지로 사용할 도커 이미지를 생성하겠습니다. 도커 허브에서 적당한 베이스 이미지를 찾으셔도 됩니다.
-- # 1. 이미지 다운로드 root@wsl-ubuntu:/mnt/d/wsl/docker/base-image# docker pull eclipse-temurin:17-jre 17-jre: Pulling from library/eclipse-temurin 5d3ecea993a0: Pull complete a3629ac5b9f4: Pull complete c4c6c77c0477: Pull complete c945adacc3c3: Pull complete 5ccdf4191aa2: Pull complete 99a5e8490fad: Download complete 8ed6fca68e87: Download complete Digest: sha256:c81561cbc09964364afa412133d8eddf55b83efe5d39a64d0a5f109359bbfccc Status: Downloaded newer image for eclipse-temurin:17-jre docker.io/library/eclipse-temurin:17-jre root@wsl-ubuntu:/mnt/d/wsl/docker/base-image# docker image ls IMAGE ID DISK USAGE CONTENT SIZE EXTRA eclipse-temurin:17-jre c81561cbc099 408MB 106MB -- # 2. 이 단계는 필요없지만 운영서버에서 도커 이미지를 빌드할 경우를 대비하여 베이스 이미지를 추출합니다.(선택사항) ---- eclipse-temurin-17.tar 파일로 추출된 것을 확인합니다. ---- 추출된 이미지를 다른 서버에 로드하기 위해서는
docker load -i <추출된_파일명> 명령어를 사용합니다. root@wsl-ubuntu:/mnt/d/wsl/docker/base-image# docker save -o eclipse-temurin-17.tar eclipse-temurin:17-jre root@wsl-ubuntu:/mnt/d/wsl/docker/base-image# ls -l total 103500 -rwxrwxrwx 1 root root 105980416 Feb 12 13:35 eclipse-temurin-17.tar -- # 3. 베이스 이미지가 정상적으로 설치되었는지 확인해 봅니다. 환경변수 $JAVA_HOME이 설정되어 있습니다.(선택사항) root@wsl-ubuntu:/mnt/d/wsl/docker/base-image# docker run -it eclipse-temurin:17-jre /bin/bash root@a1c8f8954fdd:/# cd $JAVA_HOME root@a1c8f8954fdd:/opt/java/openjdk# ll total 32 drwxr-xr-x 6 root root 4096 Feb 5 22:18 ./ drwxr-xr-x 3 root root 4096 Feb 5 22:18 ../ drwxr-xr-x 2 root root 4096 Jan 20 22:33 bin/ drwxr-xr-x 5 root root 4096 Jan 20 22:29 conf/ drwxr-xr-x 52 root root 4096 Jan 20 22:29 legal/ drwxr-xr-x 5 root root 4096 Jan 20 22:33 lib/ -rw-r--r-- 1 root root 2400 Jan 20 22:33 NOTICE -rw-r--r-- 1 root root 1626 Jan 20 22:33 release
- 윈도우즈 C: 드라이브는 Ubuntu “/mnt/c”에, 윈도우즈 D: 드라이브는 Ubuntu “/mnt/d”에 마운팅되어 있습니다. 윈도우즈와 Ubuntu 간에 파일의 복사/이동이 쉽도록 “/mnt/d”에 하위 디렉토리로 wsl을 생성하겠습니다. 앞으로 모든 작업은 “/mnt/d/wsl” 디렉토리에 진행합니다.
- 단계: Java Application을 빌드하기 위한 Dockerfile을 작성하고 빌드합니다.
- Eclipse에서 빌드한 jar 파일(pda-api.jar)을 Java Application 이미지 빌드용 디렉토리로 복사합니다.
- Java Application 이미지 빌드용 디렉토리로 이동한 후 Dockerfile를 작성합니다.
root@wsl-ubuntu:/mnt/d/wsl/docker/app-build# vi Dockerfile # 1. 베이스 이미지 설정 (Eclipse Temurin Java 17 JRE) FROM eclipse-temurin:17-jre # 2. 환경 변수 설정 (이미 설정되어 있지만, 명시적으로 관리하기 위함) # JAVA_HOME 환경변수는 Temurin 이미지에 설정되어 있으므로 생략해도 됩니다. # JVM메모리는 도커에 할당할 최대 메모리의 75%로 설정(4G*0.75=3072M) # Java Option에 관련해서는 "Java 프로세스의 상태를 진단하는 세 가지 핵심 도구" 글 참고 ENV TZ=Asia/Seoul \ LC_ALL=C.UTF-8 \ ORACLE_PW=password \ JAVA_OPTS="-server -Xms3072m -Xmx3075m -XX:+UseContainerSupport \ -Djava.awt.headless=true \ -Dfile.encoding=UTF-8 \ -XX:+HeapDumpOnOutOfMemoryError \ -XX:HeapDumpPath=/app/logs/DUMP/ \ -XX:+ExitOnOutOfMemoryError \ -Xlog:gc*:file=/app/logs/GC/pda-api_gc.log:time,uptime,level,tags:filecount=10,filesize=10M" # 3. 실행 계정 생성 및 권한 설정 # HeapDump 및 GC Log 저장 디렉토리를 생성합니다. RUN useradd -u 1004 -o -m -d /app pdaadm && \ mkdir -p /app/logs/GC /app/logs/DUMP && \ chown -R pdaadm:pdaadm /app # 4. 앱 실행에 필요한 파일 복사 # Eclipse에서 빌드한 jar 파일(pda-api.jar)을 도커 이미지 내부의 파일(app.jar)로 복사합니다. # profile 등 다른 필요한 파일들도 함께 복사합니다. COPY --chown=pdaadm:pdaadm ./pda-api.jar app.jar # 5. 도커 이미지의 작업 디렉토리 및 실행 계정 설정 WORKDIR /app USER pdaadm # 6. 컨테이너 내부 포트 개방 선언, EXPOSE 8080 # 7. 실행 명령어 (ENTRYPOINT는 CMD보다 변경이 어려워 실행형 이미지에 적합합니다) ENTRYPOINT ["sh", "-c", "exec java ${JAVA_OPTS} -jar /app/pda-api.jar --spring.profiles.active=local --spring.datasource.password=${ORACLE_PW}"]
- Java Application 이미지를 빌드합니다.
root@wsl-ubuntu:/mnt/d/wsl/docker/app-build# docker build -t pda-api:1.0 .
- 단계: 빌드된 Java Application 이미지를 추출하고 운영서버로 전송합니다.
- 빌드된 Java Application 이미지를 추출합니다.
root@wsl-ubuntu:/mnt/d/wsl/docker/app-build# docker save -o ./pda-api.tar pda-api:1.0
- FileZilla 등을 이용해서 추출된 Java Application 이미지를 운영서버로 전송합니다.
- 빌드된 Java Application 이미지를 추출합니다.
- 단계: 전송받은 Java Application 이미지로 운영서버에서 서비스를 제공합니다. 인터넷이 연결되지 않은 운영서버에서 도커 사용하는 방법을 참고바랍니다.
- 운영서버에 로그인한 후 Java Application 이미지(pda-api.tar)를 저장한 디렉토리에서 아래 명령어를 실행하여 도커 엔진에 다시 “이미지” 상태로 인식시킵니다.
$ sudo docker load -i pda-api.tar $ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE pda-api 1.0 6d27fc743837 4 minutes ago 354MB
- 먼저 업로드된 이미지를 컨테이너로 실행하는
docker run명령어의 옵션 사용법에 대해 알아보겠습니다.$ sudo docker run -d \ --name <컨테이너 이름> \ # 컨테이너 이름 지정 --restart unless-stopped \ # 컨테이너가 예기치 않게 종료되거나 서버가 재부팅되었을 때 항상 자동 재시작 --memory="4g" \ # 컨테이너가 사용할 최대 메모리를 4GB로 제한 -p <호스트 포트>:<컨테이너 포트> \ # 호스트와 컨테이너의 포트 연결(like 포트 포워딩) -v <호스트 경로>:<컨테이너 경로> \ # 호스트 디렉토리와 컨테이너 내부 디렉토리로 연결(Volume) -e "<환경변수 명>=<환경변수 값>" \ # 컨테이너 내부에서 사용할 환경 변수를 설정, " "(스페이스)로 구분 --log-opt max-size=10m \ # 로그 파일 하나당 최대 크기를 10MB로 제한 --log-opt max-file=5 \ # 보관할 로그 파일의 최대 개수를 5개로 제한 --health-cmd="curl -f http://localhost:8080/health || exit 1" \ # 컨테이너 상태점검을 위해 컨테이너 내부에서 주기적으로 실행할 명령어를 지정 --health-interval=30s \ # 상태 점검 주기(30초) <이미지 이름>:<이미지 버전> # 실행한 이미지 및 해당 이미지의 버전
- 로드된 Java Application 이미지를 컨테이너로 실행합니다
-- 컨테이너 내부의 디렉토리와 연결되는 호스트 디렉토리를 먼정 생성하고 권한을 설정합니다. $ chmod -R 777 /package/pdaadm/docker/logs $ chown -R pdaadm:pdaadm /package/pdaadm/docker/logs $ sudo docker run -d \ --name pda-api-service \ -p 8081:8080 \ -e "spring.profiles.active=local" \ -e "ORACLE_DEV_PW=dimtamain00" \ -v /package/pdaadm/docker/logs:/app/logs \ --restart always \ pda-api:1.0 $ sudo docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 05f14e43da3f pda-api:1.0 "sh -c 'java $JAVA_O…" 5 seconds ago Up 4 seconds 0.0.0.0:8081->8080/tcp, :::8081->8080/tcp pda-api-service $ sudo netstat -tnlp | grep 8081 tcp 0 0 0.0.0.0:8081 0.0.0.0:* LISTEN 1809/docker-proxy tcp6 0 0 :::8081 :::* LISTEN 1814/docker-proxy
- Java Application 서비스를 DB와 연동해야 한다면, 실행 시 DB 접속 정보를 환경변수로 넘겨주는 것이 좋습니다.
# 예시: DB 접속 정보를 실행 시점에 주입 $ sudo docker run -d \ .... -e "SPRING_DATASOURCE_URL=jdbc:oracle:thin:@db.server.ip.address:1521:ORACLE_SID" \ -e "SPRING_DATASOURCE_USERNAME=user" \ -e "SPRING_DATASOURCE_PASSWORD=pass" \ pda-api:1.0
- 운영서버에 로그인한 후 Java Application 이미지(pda-api.tar)를 저장한 디렉토리에서 아래 명령어를 실행하여 도커 엔진에 다시 “이미지” 상태로 인식시킵니다.
