1일차: 클라우드 및 Docker 개념 학습

클라우드 컴퓨팅이 필요한 이유

  1. 비용절감
    • 하드웨어 및 소프트웨어를 구입하고 데이터 센터 설치 및 운영 비용을 줄일 수 있습니다.
    • 서버 랙, 전원 및 냉각에 사용되는 전기료, 인프라 관리를 위한 IT 전문가 인건비 등도 절약됩니다.
  2. 속도향상
    • 주문형 셀프서비스로 제공되기 때문에 다양한 컴퓨팅 리소스를 몇번의 마우스 클릭으로 설정할 수 있습니다.
  3. 확장성
    • 필요할 때 적절하게 스토리지, 네트워크 대역폭 등 IT 자원을 확장할 수 있습니다.
  4. 생산성
    • 일반적인 온사이트 데이터센터에서는 하드웨어 설치, 소프트웨어 패치 및 시간이 오래걸리는 IT 운영 작업이 필요하지만, 클라우드 컴퓨팅을 사용하면 이 모든게 불필요해지므로 IT 팀은 인프라 외에 비즈니스에 집중할 수 있습니다.

Docker Compose vs Kubernetes

 

 

 

2일차: Docker 이미지 생성 실습

Docker 이미지 주요 명령어

# 현재 시스템에서 사용 가능한 모든 Docker 이미지 목록 확인
$ docker images

# 특정 이미지 다운로드
$ docker pull <이미지 이름>

# 이미지 정보 확인
$ docker inspect <이미지 이름>

# 이미지 삭제
$ docker rmi <이미지 이름>

 

 불필요한 파일 줄이기 (.dockerignore 활용)

  • .**dockerignore** 파일은 Docker 빌드 과정에서 제외할 파일과 디렉터리를 지정하는 역할을 합니다.
  • Docker는 docker build를 실행할 때, 현재 디렉터리(.)의 모든 파일을 Docker 컨텍스트에 복사합니다.
  • 이때 .dockerignore 파일을 사용하면 불필요한 파일을 제외하여 빌드 속도를 향상시키고, 보안성을 강화할 수 있습니다.
  • .dockerignore 파일이 필요한 이유
    1. 빌드 속도 향상 → 불필요한 파일을 제외하여 Docker 컨텍스트 크기를 줄임
    2. 보안 강화 → 환경 변수 파일(.env), 인증 정보(.git, node_modules) 등이 이미지에 포함되지 않도록 방지
    3. 이미지 크기 최소화 → 최적화된 Docker 이미지를 생성하여 배포 용량을 줄임

 

 

레이어 캐싱 (Layer Caching)

도커의 가장 중요한 특징 중 하나는 레이어 캐싱입니다. 이미지를 빌드할 때, Dockerfile의 각 명령어를 순서대로 실행하며 레이어를 만듭니다. 이때 명령어의 내용이 이전 빌드와 동일하다면, 새로운 레이어를 만들지 않고 기존에 만들어 두었던 레이어를 재사용합니다. 이를 '캐시(Cache)를 사용한다'고 말합니다.

  • 빌드 속도 향상: 변경되지 않은 부분은 다시 실행할 필요가 없으므로 이미지 빌드 시간이 크게 단축됩니다.
  • 효율적인 저장 공간 사용: 여러 이미지가 동일한 레이어를 공유하는 경우, 해당 레이어는 디스크에 한 번만 저장됩니다. 예를 들어, ubuntu:22.04를 기반으로 하는 10개의 다른 이미지가 있더라도, 우분투 베이스 레이어는 단 한 번만 저장됩니다.

Dockerfile을 작성할 때, 자주 변경되지 않는 내용은 앞부분에, 자주 변경되는 내용은 뒷부분에 배치하는 것이 레이어 캐싱을 효율적으로 활용하는 좋은 방법입니다. 소스 코드는 자주 바뀌므로 COPY . . 명령어는 보통 뒷부분에 위치시킵니다.

 

 

Docker 이미지 Versioning 과 Semantic Versioning

Docker 이미지 versioning

  • Docker 이미지는 태그(Tag) 를 사용하여 버전 관리를 수행합니다.
  • latest 태그를 사용할 수도 있지만, 명확한 버전 관리를 위해 시멘틱 버저닝(Semantic Versioning) 을 사용하는 것이 좋습니다.

시멘틱 버저닝(Semantic Versioning)이란

  • 시멘틱 버저닝(SemVer)은 주버전(Major), 부버전(Minor), 패치버전(Patch) 으로 구성됩니다.
    • 형식: MAJOR.MINOR.PATCH
    • MAJOR (주 버전): 호환성이 깨지는 큰 변경이 있을 때 올립니다.
      • 예: 1.5.2 → 2.0.0
      • 기존의 사용법이나 기능이 완전히 바뀌어, 이 버전을 사용하려면 내 코드도 수정해야 할 수 있다는 강력한 신호입니다. 마치 자동차 엔진이 바뀌는 것과 같습니다.
    • MINOR (부 버전): 기존 버전과 호환되면서 새로운 기능이 추가될 때 올립니다.
      • 예: 1.9.2 → 1.10.0
      • 기존 기능은 그대로 잘 작동하며, 새로운 옵션이나 기능이 추가된 경우입니다. 자동차에 새로운 내비게이션 시스템이 추가된 것과 같습니다. 기존 운전 방식에는 영향이 없습니다.
    • PATCH (패치 버전): 기존 버전과 호환되는 작은 버그 수정이 있을 때 올립니다.
      • 예: 1.5.2 → 1.5.3
      • 기능 변화 없이, 기존 기능의 오류를 바로잡은 경우입니다. 자동차의 사소한 부품 결함을 수리한 것과 같습니다.

버전 형식 설명

1.0.0 초기 릴리즈 버전
1.1.0 기능(feature) 추가 (하위 호환 유지)
1.1.1 버그 수정 (패치 버전)
2.0.0 기존 기능을 변경하거나 호환되지 않는 수정

Docker에서 Semantic Versioning 적용 예제

  • Dockerfile을 사용하여 시멘틱 버저닝을 적용할 때, 태그를 명확하게 지정합니다.
  • 시멘틱 버저닝을 활용하면 배포 관리가 쉬워지고, 특정 버전으로 롤백이 용이해집니다.
# 1.0.0 버전으로 빌드
docker build --build-arg PROFILE=dev -t spring-docker:1.0.0 .

# 1.0.1 버전으로 빌드 (패치 업데이트 포함)
docker build --build-arg PROFILE=dev -t spring-docker:1.0.1 .

 

3일차: Docker 네트워크 및 데이터 관리

 

  • Docker 네트워크 개념 및 종류 이해
  • 컨테이너 간 네트워크 설정 및 통신 실습
  • Docker 볼륨을 활용한 데이터 관리 실습
  • 보안 및 성능 최적화 기법 적용

1.3 컨테이너 간 기본 네트워크 통신 확인

 

# 현재 Docker 네트워크 확인
docker network ls

# 사용자 지정 브리지 네트워크 생성
# sleep infinity : 컨테이너 내부에서 종료되지 않는 프로세스를 실행하여 유지
docker run -d --name svc1 --network bridge busybox sleep infinity
docker run -d --name svc2 --network bridge busybox sleep infinity

docker exec -it svc1 ping svc2

-------------------------------------------------
ping: bad address 'svc2'

 

  • 기본 bridge 네트워크에서 컨테이너 간 직접 통신이 안 되는 이유
    1. 기본 bridge 네트워크에서는 컨테이너 이름 기반 DNS 해석이 지원되지 않음
    2. IP 주소를 직접 사용해야 하지만, IP는 컨테이너 재시작 시 변경될 수 있어 관리가 어려움
    3. 사용자 정의 네트워크를 만들면 컨테이너 이름을 통해 자동으로 통신 가능
  • 해결책
    • 기본 bridge 네트워크를 사용할 경우, 컨테이너 간 통신 시 IP 주소를 사용해야 합니다.
    • 컨테이너 이름으로 통신하려면 사용자 정의 네트워크(docker network create <네트워크명>)를 사용해야 합니다.

 

4일차: Docker 를 활용한 Log 관리

 

 

1. 표준 로그 스트림 및 출력 관리

1.1 표준 에러 스트림과 표준 출력 스트림

  1. 컨테이너 실행 및 로그 생성
    • sh -c 명령어를 통해 stdout과 stderr로 각각 로그를 출력합니다.
    • echo "stderr log" >&2는 표준 에러로 메시지를 보냅니다.
  2. docker run --name log-test -d alpine sh -c ' for i in $(seq 1 10); do echo "$i: stdout log"; echo "$i: stderr log" >&2; done'
  3. 로그 확인하기
    • 실행 중인 컨테이너의 모든 로그 출력
    docker logs log-test
    
    • 최근 5개의 로그 출력
    docker logs --tail 5 log-test
    
  1. 실시간 로그 스트림 확인
    • f 옵션을 사용하면 컨테이너의 실시간 로그 스트림을 확인할 수 있습니다.
  2. docker logs -f log-test
  1. 로그 출력 시 타임스탬프 포함
    • 각 로그에 타임스탬프를 추가하여 출력합니다.
    docker logs --timestamps log-test
    
  2. 실습 종료 및 컨테이너 정리

docker stop log-test && docker rm log-test

2. 컨테이너 로그 수집 및 관리

2.1 syslog 드라이버를 이용해 로그 전송 설정하기

Docker 컨테이너의 로그를 외부 syslog 서버로 전송 설정합니다.

docker run --log-driver=syslog --log-opt syslog-address=udp://localhost:514 -d ubuntu echo "Logging to syslog"

2.2 로그 로테이션 설정

Docker 컨테이너의 로그 드라이버는 기본적으로 json-file을 사용하며, 이 드라이버는 로그 로테이션 옵션이 있습니다. max-size와 max-file 옵션을 사용하여 로그 파일의 최대 크기와 보관할 로그 파일의 수를 제어할 수 있습니다.

# Docker 컨테이너를 로그 로테이션 설정과 함께 실행
docker run -d \\
  --name=log-rotation-test \\
  --log-opt max-size=10m \\
  --log-opt max-file=3 \\
  ubuntu bash -c 'while true; do echo "$(date) - Writing logs to fill up space..."; sleep 1; done'
  
# 로그 확인
docker logs -f log-rotation-test

# 종료 
docker stop log-rotation-test
docker rm log-rotation-test

2.3 로그 모니터링 실습

2.3.1 로그 모니터링 스크립트 생성

#!/bin/bash

# 첫 번째 인자로 컨테이너 이름을 받음
CONTAINER_NAME=$1
# 로그 라인 수 임계값 설정
THRESHOLD=1000

# 무한 루프로 계속 모니터링
while true; do
    # 현재 컨테이너의 로그 라인 수를 계산
    LOG_SIZE=$(docker logs $CONTAINER_NAME 2>&1 | wc -l)
    
    # 현재 시간 저장
    CURRENT_TIME=$(date "+%Y-%m-%d %H:%M:%S")
    
    # 로그 크기가 임계값을 초과하면 경고
    if [ $LOG_SIZE -gt $THRESHOLD ]; then
        echo "[$CURRENT_TIME] Warning: Log size ($LOG_SIZE lines) exceeds threshold ($THRESHOLD) for $CONTAINER_NAME"
        
        # 선택적: 관리자에게 이메일 발송
        # mail -s "Docker Log Alert" admin@example.com <<< "Container $CONTAINER_NAME log size exceeds threshold"
    else
        echo "[$CURRENT_TIME] Log size ($LOG_SIZE lines) is normal for $CONTAINER_NAME"
    fi
    
    # 1초 대기
    sleep 1
done

2.3.2 실습용 로그 생성 컨테이너 생성

# 로그를 지속적으로 생성하는 테스트용 Dockerfile
cat > Dockerfile << 'EOF'
FROM ubuntu:20.04

RUN apt-get update && apt-get install -y stress

CMD while true; do date; echo "Test log message"; sleep 1; done
EOF

# 이미지 빌드
docker build -t log-generator .

# 컨테이너 실행
docker run -d --name log-test1 log-generator

2.3.3 모니터링 실행 및 테스트

# 모니터링 스크립트 실행
./monitor-logs.sh log-test1

# 별도 터미널에서 로그 확인
docker logs -f log-test1

2.3.4 모니터링 설정 (확장편)

#!/bin/bash

CONTAINER_NAME=$1
THRESHOLD=1000
LOG_FILE="container_logs.txt"
ALERT_EMAIL="admin@example.com"

monitor_logs() {
    LOG_SIZE=$(docker logs $CONTAINER_NAME 2>&1 | wc -l)
    CURRENT_TIME=$(date "+%Y-%m-%d %H:%M:%S")
    DISK_USAGE=$(docker inspect $CONTAINER_NAME --format='{{.LogPath}}' | xargs du -h 2>/dev/null | cut -f1)
    
    echo "[$CURRENT_TIME] Container: $CONTAINER_NAME" >> $LOG_FILE
    echo "Log lines: $LOG_SIZE" >> $LOG_FILE
    echo "Disk usage: $DISK_USAGE" >> $LOG_FILE
    
    if [ $LOG_SIZE -gt $THRESHOLD ]; then
        MESSAGE="Warning: Container $CONTAINER_NAME has exceeded log threshold
        Current size: $LOG_SIZE lines
        Disk usage: $DISK_USAGE
        Time: $CURRENT_TIME"
        
        echo "$MESSAGE" >> $LOG_FILE
        echo "$MESSAGE" | mail -s "Docker Log Alert" $ALERT_EMAIL
        
        # 로그 백업 및 클리어
        docker logs $CONTAINER_NAME > "${CONTAINER_NAME}_logs_${CURRENT_TIME}.txt"
        docker container restart $CONTAINER_NAME
    fi
}

# 메인 모니터링 루프
while true; do
    if docker ps | grep -q $CONTAINER_NAME; then
        monitor_logs
    else
        echo "[$CURRENT_TIME] Container $CONTAINER_NAME is not running!" >> $LOG_FILE
    fi
    sleep 60
done
  • 로그용 Dockerfile 및 로그 생성 스크립트 작성
# 로그 생성용 Dockerfile 생성
cat > Dockerfile << 'EOF'
FROM ubuntu:20.04

# 스트레스 테스트 도구 설치
RUN apt-get update && apt-get install -y stress

# 로그 생성 스크립트
COPY generate-logs.sh /
RUN chmod +x /generate-logs.sh

CMD ["/generate-logs.sh"]
EOF

# 로그 생성 스크립트 작성
cat > generate-logs.sh << 'EOF'
#!/bin/bash

while true; do
    date
    echo "Application log: Process running"
    echo "System status: OK"
    echo "Memory usage: $(free -m | grep Mem | awk '{print $3}') MB"
    sleep 1
done
EOF

# 이미지 빌드
docker build -t log-generator .

# 컨테이너 실행
docker run -d --name test-container log-generator
  • 모니터링 실행 및 테스트
# 터미널 1: 모니터링 스크립트 실행
sh advanced-monitor-logs.sh test-container

# 터미널 2: 로그 생성 테스트
docker exec -it test-container bash -c 'for i in {1..1500}; do echo "Test log entry $i"; done'
  • 로그 확인 및 분석
# 모니터링 로그 확인
cat container_logs.txt

# 컨테이너 로그 확인
docker logs test-container

 

3. Docker 디스크 사용량 모니터링 실습

3.1 기본 디스크 사용량 모니터링

# Docker 전체 디스크 사용량 확인
docker system df

# 상세한 디스크 사용량 확인
docker system df -v

# 실시간 디스크 사용량 모니터링 스크립트 생성
cat > monitor-disk-usage.sh << 'EOF'
#!/bin/bash

while true; do
    echo "=== Docker 디스크 사용량 모니터링 === ($(date))"
    echo "1. 컨테이너 디스크 사용량:"
    docker ps --size --format "table {{.Names}}\\t{{.Size}}\\t{{.State}}"
    
    echo -e "\\n2. 이미지 디스크 사용량:"
    docker system df -v | grep "Images space"
    
    echo -e "\\n3. 볼륨 디스크 사용량:"
    docker system df -v | grep "Volumes space"
    
    echo -e "\\n4. 빌드 캐시 사용량:"
    docker system df -v | grep "Build cache"
    echo "======================================="
    sleep 60
done
EOF

chmod +x monitor-disk-usage.sh

3.2 테스트용 컨테이너 생성 및 모니터링

# 테스트용 컨테이너 생성
docker run -d --name disk-test-1 ubuntu:20.04 tail -f /dev/null
docker run -d --name disk-test-2 nginx

# 데이터 생성 스크립트
cat > generate-data.sh << 'EOF'
#!/bin/bash

for i in {1..10}; do
    echo "Generating data file $i..."
    docker exec disk-test-1 dd if=/dev/zero of=/tmp/file$i bs=1M count=100
    sleep 1
done
EOF

chmod +x generate-data.sh

3.3 디스크 모니터링 스크립트 작성

cat > advanced-disk-monitor.sh << 'EOF'
#!/bin/bash

LOG_FILE="disk_usage_log.txt"
THRESHOLD_PERCENT=80
ALERT_EMAIL="admin@example.com"

log_message() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOG_FILE
}

get_container_sizes() {
    docker ps -s --format "{{.Names}}: {{.Size}}" | while read line; do
        log_message "Container $line"
    done
}

check_disk_usage() {
    # Docker 루트 디렉토리 사용량 확인
    DOCKER_ROOT=$(docker info | grep "Docker Root Dir" | cut -d: -f2 | tr -d ' ')
    USAGE_PERCENT=$(df -h $DOCKER_ROOT | awk 'NR==2 {print $5}' | tr -d '%')
    
    log_message "Docker root directory ($DOCKER_ROOT) usage: ${USAGE_PERCENT}%"
    
    if [ $USAGE_PERCENT -gt $THRESHOLD_PERCENT ]; then
        MESSAGE="Warning: Docker disk usage is at ${USAGE_PERCENT}%"
        log_message "$MESSAGE"
        
        # 가장 큰 컨테이너 5개 리스트
        log_message "Top 5 largest containers:"
        docker ps -s --format "{{.Size}}\\t{{.Names}}" | sort -hr | head -n 5 | \\
            while read line; do
                log_message "$line"
            done
        
        # 사용하지 않는 리소스 정리 추천
        log_message "Recommended cleanup commands:"
        log_message "docker system prune -f"
        log_message "docker volume prune -f"
        log_message "docker image prune -a -f"
    fi
}

monitor_volumes() {
    log_message "Volume usage:"
    docker volume ls -q | while read vol; do
        USAGE=$(docker run --rm -v $vol:/vol alpine du -sh /vol)
        log_message "Volume $vol: $USAGE"
    done
}

# 메인 모니터링 루프
while true; do
    log_message "=== Starting disk usage check ==="
    check_disk_usage
    get_container_sizes
    monitor_volumes
    log_message "=== Completed disk usage check ==="
    echo -e "\\n"
    sleep 300  # 5분 간격으로 체크
done
EOF

chmod +x advanced-disk-monitor.sh

3.4 실습 시나리오

3.4.1 모니터링 시작

# 터미널 1: 기본 모니터링 실행
./monitor-disk-usage.sh

# 터미널 2: 데이터 생성
./generate-data.sh

3.4.2 모니터링 테스트

# 터미널 1: 고급 모니터링 실행
./advanced-disk-monitor.sh

# 터미널 2: 대용량 파일 생성
docker run -d --name big-data-test ubuntu:20.04 tail -f /dev/null
docker exec big-data-test dd if=/dev/zero of=/bigfile bs=1G count=2

3.4.3 디스크 정리

# 사용하지 않는 리소스 정리
docker system prune -f

# 사용하지 않는 볼륨 정리
docker volume prune -f

# 사용하지 않는 이미지 정리
docker image prune -a -f

# 정리 후 사용량 확인
docker system df -v

3.4.4 컨테이너 별 상세 모니터링

# 컨테이너별 디스크 사용량 모니터링 스크립트
cat > container-disk-monitor.sh << 'EOF'
#!/bin/bash

echo "=== Container Disk Usage Details ==="
docker ps --format "{{.Names}}" | while read container; do
    echo "Container: $container"
    echo "Size details:"
    docker ps -s --filter "name=$container" --format "Virtual Size: {{.Size}}"
    echo "Top 5 largest directories:"
    docker exec $container du -h / 2>/dev/null | sort -hr | head -n 5
    echo "------------------------"
done
EOF

chmod +x container-disk-monitor.sh
./container-disk-monitor.sh
LIST

+ Recent posts