Recording/멋쟁이사자처럼 BE 13기

[멋쟁이사자처럼 부트캠프 TIL 회고] BE 13기_73일차_"Docker 이미지"

LEFT 2025. 3. 25. 17:59

🦁멋쟁이사자처럼 백엔드 부트캠프 13기 🦁
TIL 회고 - [73]일차

🚀73차에는 Docker로 사용자 정의 이미지를 만들어 Docker hub로 공유하는 것도 학습해볼 수 있었다.

학습 목표 : 샘플 프로젝트를 통해 이미지로 태그(버전)관리를 해보고 별도의 이미지를 만들어낼 수 있다.

학습 과정 : 회고를 통해 작성


❓EC2 vs S3

➡️아마존 웹 서비스(AWS)와 관련된 개념

1. EC2 (Elastic Compute Cloud)

  • AWS에서 제공하는 가상 서버 서비스
  • EC2는 물리적인 서버대신 클라우드에서 가상 머신(VM)을 실행할 수 있는 서비스
    ex.
    도커 컨테이너를 실행하려면 호스트 머신(서버)이 필요한데 EC2는 클라우드에서 가상 서버를 제공하므로
    여기에 Docker를 설치하고 컨테이너를 실행할 수 가능

  • Docker + EC2 과정 흐름
    1. AWS에서 EC2 인스턴스를 생성
    2. EC2에 SSH로 접속
    3. 도커를 설치하고 실행
    4. 도커 컨테이너를 배포하여 실행

2. S3 (Simple Storage Service)

  • AWS에서 제공하는 오브젝트 스토리지 서비스
  • 파일(이미지, 동영상, 로그, 데이터 등)을 저장하는 클라우드 저장소
  • 도커 컨테이너가 실행 시 데이터를 저장하거나 불러올 필요가 있으므로 장기적인 데이터 보관에 S3를 활용

  • Docker + S3 과정 흐름
    1. 도커 이미지 저장: 도커 이미지를 S3에 백업할 수 있음
    2. 로그 저장: 컨테이너에서 생성하는 로그를 S3에 저장

포트 매핑

  • 컨테이너 내부의 포트(ex. 80)는 호스트에서 직접 접근할 수 없으며,
  • 외부로부터 접근하려면 포트 매핑( -p ) 옵션으로 호스트 포트와 연결
  • 단순 매핑
    docker run -d -p 8080:80 --name webserver nginx
    ➡️컨테이너 내부 80 포트를 호스트 8080 과 매핑
    ➡️호스트 IP(ex. localhost )의 8080 포트로 접근하면, 컨테이너의 80 포트 웹서버 에 연결

  • 포트 범위나 프로토콜 지정
    docker run -d -p 5000-5003:5000-5003/tcp myapp
    ➡️여러 포트를 일괄 매핑하거나, tcp/udp 프로토콜을 명시 가능

  • Bridge 네트워크를 사용하므로, -p 없이는 외부로 노출되지 않음

ex.

- local에서 접속시 DB URL이 어떻게 될지 ➡️jdbc:mysql://localhost:3307/testdb
로컬에서 접속할때 앞에 있는 것을 사용 (3307:3306 에서 3307)

- 컨테이너에서 접속 시 DB URL이 어떻게 될지 ➡️jdbc:mysql://mymysql:3306/testdb
로컬호스트로 접속이 안되기때문에 mysql로 가야하는데 mysql은 내부적으로 3306으로 동작하고 있다.
따라서 mymysql:3306 으로 해주어야한다.

- 컨테이너 내에서는 3306처럼 동작하고 컨테이너 밖에서는 3307로 접근하고 싶을때를 의미


Docker DNS / 호스트명

  • 컨테이너 이름으로 통신
  • Docker의 브리지네트워크에서 각 컨테이너는 서로를 컨테이너 이름으로 접근가능하도록 설정

 

컨테이너 호스트명 설정

  • --hostname 옵션으로 호스트명을 명시적으로 지정 가능
  • docker run -d --name webapp --hostname webapp.local --network my-bridge mywebimage
    ➡️
    webapp.local이 hostname으로 지정된 것

    - 컨테이너 이름( --name ) : Docker DNS에 등록될 때 쓰이는 주요 식별자
    - hostname( --hostname ) : 컨테이너 내부 OS가 인식하는 호스트명( /etc/hostname 등 )

도커 관련 명령어

docker network create my-bridg
➡️
새로운 사용자 정의 브리지 네트워크(my-bridge)를 생성

docker run -d --network my-bridge --name container1 nginx
➡️
container1이라는 이름을 가진 컨테이너를 my-bridge 네트워크에 연결하여 실행

docker run -it --network my-bridge --name container2 ubuntu bash
➡️container2에서도 my-bridge 네트워크를 사용
컨테이너 이름(container1)을 직접 사용해서 접근 가능


이미지 Image

 

레이어(Layer)

  • Docker이미지란 여러 레이어가 쌓여있는 형태
  • 각 레이어가 파일 시스템 변경사항 (새파일추가, 수정, 삭제 등)을 보관
  • 이 레이어들은 읽기전용, 합쳐셔 하나의 최종 파일시스템 상태를 구성
FROM ubuntu:20.04 # (레이어 1)
RUN apt-get update && apt-get install -y python3 # (레이어 2)
COPY . /app # (레이어 3)
CMD ["python3", "/app/app.py"]
version: '3.8'
services:
  spring-app:
    build: .
    container_name: juunb-spring-container
    ports:
      - "9999:8080"
    environment:
      - GITHUB_USER=${JUUNB_GITHUB_USER}
      - GITHUB_TOKEN=${JUUNB_GITHUB_TOKEN}
    command: /bin/bash -c "/app/start.sh"
  • 이 docker-compose.yml 파일에서는 Dockerfile을 가지고 이미지를 생성해내는 명령이 build인 것

 

빌드 : docker build -t myimage:latest .
  • -t : 태그를 의미
  • myimage : 이미지의 이름
  • latest : 버전명 (마지막버전을 의미)
  • . (온점) : 현재 디렉토리에있는 Dockerfile을 기준으로 이미지를 만들어달라는 것

  • docker history myimage:latest
    ➡️
    이미지 레이어 정보 확인하기

▶️실습 - Docker 브릿지 (네트워크)

  • 네트워크 만들기 (네트워크 생성)
  • 이 네트워크 브릿지 위에 mysql 컨테이너 하나 생성하기
C:\\Workspace\\docker\\docker-mysql>docker network create --driver bridge spring-net
cb1e051eca1fd9fb99e5c159bfafd7ba084f75d33e163d0b57cb47d319a4f0cd
  • spring-net이라는 네트워크 브릿지 만들기

  • 브릿지가 잘생성되었는지 확인
docker run -d ^
	--name mymysql ^
	--network spring-net ^
	-e MYSQL_ROOT_PASSWORD=rootpass ^
	-e MYSQL_DATABASE=testdb ^
	-e MYSQL_USER=testuser ^
	-e MYSQL_PASSWORD=testpass ^
	-p 3308:3306 ^
	mysql:8
  • 3308로 만들어준다 (3307은 이미 사용중)

  • 현재 한국기준 시간과는 차이가 있다.
  • docker run 명령어는 도커 이미지(image)를 만든 것이 아니라, 컨테이너(container)를 실행한 것

  • 도커 이미지(Docker Image) : docker build 명령어를 사용하여 생성
    ➡️ex. mysql:8 (이미 존재하는 공식 MySQL 이미지)

  • 도커 컨테이너(Docker Container)
    ➡️
    docker run 명령어로 실행
    ➡️ 컨테이너는 실행 중 상태를 가지며, 중지되거나 삭제될 수 있음
    ex. docker run -d --name mymysql mysql:8

  • docker network create spring-net
    ➡️
    사용자 정의 네트워크 생성 (컨테이너 간 통신)

  • docker run -d --name mymysql --network spring-net -e MYSQL_DATABASE=testdb -p 3308:3306 mysql:8
    ➡️기존 mysql:8 이미지를 기반으로 컨테이너 실행
    ➡️
    이미지를 만든 것이 아니라, 기존 mysql:8 이미지를 사용하여 컨테이너를 실행한 것

▶️실습 - mysql:8 이미지가 아닌 사용자 정의 이미지 만들기

  • MySQL 설정이 포함된 커스텀 도커 이미지를 만들고 싶다면, Dockerfile을 사용해서 빌드
# 1) MySQL 공식 이미지
FROM mysql:8

# 2) 환경 변수 설정
ENV TZ=Asia/Seoul \\
    DEBIAN_FRONTEND=noninteractive

# 3) tzdata 설치 (microdnf)
RUN microdnf -y install tzdata && \\
    ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \\
    echo $TZ > /etc/timezone && \\
    microdnf clean all

# 4) MySQL 서버 실행 시 파라미터로 시간대 및 문자셋 설정
CMD ["mysqld", \\
     "--character-set-server=utf8mb4", \\
     "--collation-server=utf8mb4_unicode_ci", \\
     "--default-time-zone=+09:00"]
  • 환경변수 설정으로 아시아/서울지역의 시각으로 맞춰주겠다는 것

 

docker build -t mymysql .

  • 이미지 이름을 mymysql로 할 것
  •  .  : 현재 디렉토리 안에 이미지로 만들 Dockerfile이 있음을 의미
    (다른 경로에 존재하면 그 다른 경로를 지정해주어야함)

    태그를 지정해주지 않으면 기본값으로 최신 (latest)를 받아온 것

  • docker images로 확인해보면 mymysql이미지가 잘 생성된 것을 확인 가능

  • mymysql처럼 바꿔주어 사용자 정의 이미지를 활용한다.

  • 한국 시각으로 잘 적용된 것을 확인할 수 있다.

▶️실습 - 샘플 프로젝트 클론 후 Docker 실행

 

  • application-prod.yml 처럼 profile을 실행하기 위한 product 설정파일을 만들어준다.

  • 설정을 바꿔주어야한다. 또 이것을 이미지로 만들어서 Docker 컨테이너에서 동작하게 만들면 될 것

application-prod.yml 파일을 별도로 생성한 이유

  • Spring Boot에서 application-prod.yml을 따로 만들어주는 이유
    ➡️환경(Profiles)에 따라 다른 설정을 적용하기 위함

  • 이러한 Spring Profiles 기능을 사용하면 특정 환경에서 다른 설정을 적용 가능
  • Spring Profiles : Spring Boot에서는 spring.profiles.active 속성을 이용해 다른 환경별 설정을 자동으로 적용 가능

  • application.yml : 기본 설정
    application-dev.yml : 개발 환경 설정
    application-prod.yml : 운영(프로덕션) 환경 설정

    환경별로 다른 설정을 분리하여 관리 (=코드를 수정하지 않고 환경만 바꿔서 실행 가능)

 

  • ./gradlew build -x test ➡️test를 제외하고 빌드하겠다는 것

  • docker build -t my-todo-app:1.0 .
    ➡️현재 디렉토리에서 my-todo-app 이라는 이미지를 만드는데 버전은 1.0

  • $ docker run -d --name todoApp -p 8888:8080 my-todo-app:1.0 37d196cd9b5d415e024f41c59758cf386d4937f9edf1587fefc46378e3ebf490
    ➡️-d 백그라운드 실행으로 이름은 todoAp, 8080포트를 8888로 연결, my-todo-app 은 1.0버전으로 매핑

▶️실습 - 버전 다른 이미지 만들기

  • ./gradlew build -x test로 빌드
  • docker build -t my-todo-app:2.0 .
    ➡️현재디렉토리에 my-todo-app이라는 이름의 2.0 버전 이미지를 만들어준다.

  • images를 확인해보면 이처럼 TAG로 1.0, 2.0이 공존하고 있음을 알 수 있다.

  • --network spring-net 옵션과 함께 run
    ➡️logs를 확인해보면 서버가 잘 실행되고 있는 것을 결과로 확인 가능

▶️실습 - Docker hub에 이미지 올리기

  • docker login 으로 Login Succeeded 가능
  • docker tag my-todo-app:3.0 juunb/my-todo-app:3.0
    ➡️docker hub에서 사용할 아이디와함께 태깅을 진행

  • docker push를 통해 올리기 진행

▶️실습 - 이미지 가져오기

  • Image Id를 활용하여 가져온
  • docker run -d —name [지정이름] -p [외부포트:내부포트] —network [브릿지이름] [이미지ID]
    docker run -d --name whois -p 8887:8080 --network spring-net 7923a1787fa4
    ➡️지정한 포트로 접속이 가능할 것

🚀회고 결과 :

사용자 정의 이미지를 만들고 Docker hub를 활용하는 연습을 회고시간을 통해 해볼 수 있었다.
필요한 설정들을 넣어서 이미지를 만드는 연습을 해볼 수 있었다.

향후 계획 : 

- 이미지 버전 관리나 EC2, S3에 대해 공부