RHEL 배포 설치 및 자동화

Red Hat Enterprise LinuxBeginner
지금 연습하기

소개

이 랩에서는 Docker 를 사용하여 Red Hat Enterprise Linux (RHEL) 9 컨테이너를 배포하고 자동화하는 기본 사항을 배우게 됩니다. 현대 클라우드 네이티브 배포는 기존 가상 머신보다 컨테이너화된 RHEL 환경에 점점 더 의존하고 있습니다. 먼저, 컨테이너 형식으로 엔터프라이즈급 RHEL 환경을 제공하는 Red Hat 의 Universal Base Images (UBI) 를 살펴보겠습니다.

전통적인 Kickstart 개념이 컨테이너 자동화로 어떻게 변환되는지 살펴보고, 설치 구성을 미러링하는 사용자 지정 Dockerfile 을 생성하며, 자동화된 배포 스크립트를 구축합니다. 이 랩을 마치면 RHEL 컨테이너를 효율적으로 배포하고 현대 클라우드 환경에서 일관되고 반복 가능한 배포를 위해 프로세스를 자동화하는 방법을 이해하게 될 것입니다.

이것은 가이드 실험입니다. 학습과 실습을 돕기 위한 단계별 지침을 제공합니다.각 단계를 완료하고 실무 경험을 쌓기 위해 지침을 주의 깊게 따르세요. 과거 데이터에 따르면, 이것은 초급 레벨의 실험이며 완료율은 89%입니다.학습자들로부터 98%의 긍정적인 리뷰율을 받았습니다.

Red Hat Universal Base Images (UBI) 탐색

이 단계에서는 RHEL 을 기반으로 하는 엔터프라이즈급 컨테이너 이미지인 Red Hat 의 Universal Base Images (UBI) 를 탐색합니다. 전체 가상 머신이 필요한 기존 RHEL 설치와 달리, UBI 이미지는 가볍고 이식 가능한 컨테이너에서 RHEL 환경을 제공합니다. 이러한 이미지는 자유롭게 재배포할 수 있으며 현대 클라우드 네이티브 애플리케이션을 위해 설계되었습니다.

Red Hat 은 다양한 사용 사례에 최적화된 여러 UBI 변형을 제공합니다. redhat/ubi9 이미지는 dnf 패키지 관리자를 포함하는 전체 RHEL 기반 컨테이너 환경을 제공하여 소프트웨어 설치 및 시스템 자동화가 필요한 애플리케이션에 적합합니다.

먼저, 이 랩을 위해 준비된 Red Hat 컨테이너 구성 템플릿을 살펴보겠습니다. 이 파일은 기존 Kickstart 개념이 컨테이너 환경으로 어떻게 변환되는지 보여줍니다.

sudo cat /etc/labex/rhel-container-config.cfg

기존 설치 개념을 미러링하는 Dockerfile 스타일의 구성을 보여주는 출력을 보게 됩니다.

## RHEL Container Configuration Template
## Based on traditional Kickstart concepts adapted for containers

## Base image specification
FROM redhat/ubi9

## System locale and timezone
ENV LANG=en_US.UTF-8
ENV TZ=America/New_York

## User configuration
ENV CONTAINER_USER=labex
ENV ROOT_PASSWORD=redhat

## Package installation
## Packages: httpd, curl (container-appropriate equivalents)
RUN dnf install -y --allowerasing httpd curl && \
    dnf clean all

## Service configuration
EXPOSE 80

## Startup command
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]

이제 사용 가능한 Red Hat UBI 이미지를 살펴보겠습니다. 먼저 Docker 가 실행 중이고 접근 가능한지 확인합니다.

docker --version

전체 RHEL 기반 컨테이너 환경을 제공하는 Red Hat UBI 9 이미지를 가져옵니다.

docker pull redhat/ubi9

다음과 유사한 출력을 볼 수 있습니다.

Using default tag: latest
latest: Pulling from redhat/ubi9
Digest: sha256:...
Status: Downloaded newer image for redhat/ubi9:latest
docker.io/redhat/ubi9:latest

가져오기가 성공했는지 확인하기 위해 다운로드된 이미지를 나열합니다.

docker images redhat/ubi9

출력은 이미지에 대한 세부 정보를 표시합니다.

REPOSITORY      TAG       IMAGE ID       CREATED      SIZE
redhat/ubi9     latest    b1c2d3e4f5g6   5 days ago   216MB

이제 RHEL 환경을 탐색하기 위해 기본 컨테이너를 실행해 보겠습니다.

docker run -it --rm redhat/ubi9 /bin/bash

컨테이너 내부에서 운영 체제 버전을 확인하여 RHEL 환경을 탐색합니다.

cat /etc/redhat-release

다음과 유사한 내용을 볼 수 있습니다.

Red Hat Enterprise Linux release 9.6 (Plow)

사용 가능한 패키지 관리자를 확인합니다.

dnf --version

다음을 입력하여 컨테이너를 종료합니다.

exit

사용자 정의를 위해 템플릿 구성을 프로젝트 디렉토리로 복사합니다.

sudo cp /etc/labex/rhel-container-config.cfg ~/project/rhel-container.dockerfile
sudo chown labex:labex ~/project/rhel-container.dockerfile

파일이 성공적으로 복사되었는지 확인합니다.

ls -l ~/project/rhel-container.dockerfile

이제 Red Hat UBI 이미지를 성공적으로 탐색했으며 다음 단계에서 사용자 지정 컨테이너 구성을 만들 준비가 되었습니다.

맞춤형 RHEL 컨테이너 구성 생성

이 단계에서는 Red Hat UBI 이미지를 기반으로 사용자 지정 Dockerfile 을 생성합니다. 이 프로세스는 자동 설치를 위해 Kickstart 파일을 사용자 지정하는 방법과 유사하지만 컨테이너 환경에 맞게 조정되었습니다. Dockerfile 은 일관된 RHEL 컨테이너 배포를 생성하기 위한 자동화 템플릿 역할을 합니다.

먼저, 프로젝트 디렉토리에 있는지 확인합니다.

cd ~/project

자동화된 RHEL 컨테이너 배포를 위해 새롭고 더 구체적인 Dockerfile 을 생성합니다.

cp rhel-container.dockerfile rhel9-automated.dockerfile

두 파일이 존재하는지 확인합니다.

ls -l *.dockerfile

두 파일을 모두 볼 수 있습니다.

-rw-r--r--. 1 labex labex 423 Jul 22 10:30 rhel-container.dockerfile
-rw-r--r--. 1 labex labex 423 Jul 22 10:35 rhel9-automated.dockerfile

이제 사용자 지정을 시작하기 전에 새 Dockerfile 을 열어 구조를 검토합니다.

nano rhel9-automated.dockerfile

파일 내부에서 Kickstart 지시어에 해당하는 컨테이너를 볼 수 있습니다.

  • FROM 지시어: 기본 RHEL 이미지 (설치 미디어에 해당) 를 지정합니다.
  • ENV 지시어: 환경 변수를 설정합니다 (시스템 구성에 해당).
  • RUN 지시어: 이미지 빌드 중에 명령을 실행합니다 (패키지 설치에 해당).
  • EXPOSE 및 CMD: 서비스 및 시작을 구성합니다 (서비스 구성에 해당).

지금은 Ctrl+X를 눌러 편집기를 종료하고 사용자 지정 단계로 진행합니다.

이 구조를 이해하면 자동화된 VM 설치를 위해 Kickstart 파일을 사용자 지정하는 것처럼 특정 배포 요구 사항을 충족하도록 컨테이너 구성을 사용자 지정하는 다음 단계를 준비할 수 있습니다.

자동 배포를 위한 컨테이너 구성 사용자 정의

이 단계에서는 rhel9-automated.dockerfile의 내용을 자동화된 RHEL 컨테이너 배포를 위한 사용자 지정 구성으로 바꿉니다. 이 프로세스는 Kickstart 파일을 사용자 지정하는 것과 유사하지만, Docker 의 선언적 접근 방식을 사용하여 컨테이너 환경 및 서비스를 정의합니다.

먼저, 프로젝트 디렉토리에 있는지 확인합니다.

cd ~/project

이제 rhel9-automated.dockerfile의 전체 내용을 바꿔서 완전한 사용자 지정 Dockerfile 을 생성합니다.

cat > rhel9-automated.dockerfile << 'EOF'
## RHEL 9 Automated Container Deployment
## Based on Red Hat Universal Base Image 9
FROM redhat/ubi9:latest

## Container metadata
LABEL maintainer="LabEx Admin"
LABEL description="Automated RHEL 9 container with web services"
LABEL version="1.0"

## System locale and timezone configuration
ENV LANG=en_US.UTF-8
ENV TZ=America/New_York
ENV CONTAINER_USER=labex
ENV CONTAINER_UID=1001

## Package installation and system configuration
RUN dnf update -y \
  && dnf install -y --allowerasing \
    httpd \
    curl \
    tar \
    gzip \
  && dnf clean all \
  && rm -rf /var/cache/dnf

## Create non-root user for security
RUN useradd -u ${CONTAINER_UID} -m -s /bin/bash ${CONTAINER_USER} \
  && echo "${CONTAINER_USER}:labex" | chpasswd

## Configure Apache for container environment
RUN sed -i 's/Listen 80/Listen 8080/' /etc/httpd/conf/httpd.conf \
  && chown -R ${CONTAINER_USER}:${CONTAINER_USER} /var/log/httpd /var/run/httpd

## Create startup script
RUN echo '#!/bin/bash' > /start.sh \
  && echo 'echo "RHEL Container started on $(date)" > /var/www/html/index.html' >> /start.sh \
  && echo 'echo "<h1>RHEL 9 Container</h1><p>Deployed via automated configuration</p>" >> /var/www/html/index.html' >> /start.sh \
  && echo 'exec /usr/sbin/httpd -D FOREGROUND' >> /start.sh \
  && chmod +x /start.sh

## Switch to non-root user
USER ${CONTAINER_USER}

## Expose port and define startup
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:8080/ || exit 1

CMD ["/start.sh"]
EOF

이제 이 사용자 지정 Dockerfile 의 구조를 살펴보고 각 섹션이 Kickstart 구성의 다른 부분과 동일한 목적을 어떻게 수행하는지 이해해 보겠습니다.

1. 기본 이미지 및 메타데이터 섹션:

## RHEL 9 Automated Container Deployment
## Based on Red Hat Universal Base Image 9
FROM redhat/ubi9:latest

## Container metadata
LABEL maintainer="LabEx Admin"
LABEL description="Automated RHEL 9 container with web services"
LABEL version="1.0"

이 섹션은 Kickstart 파일에서 설치 미디어 및 기본 시스템 정보를 지정하는 것과 같습니다. FROM 지시어는 기본 RHEL 이미지를 지정하고, LABEL 지시어는 컨테이너에 대한 메타데이터를 제공합니다.

2. 환경 구성:

## System locale and timezone configuration
ENV LANG=en_US.UTF-8
ENV TZ=America/New_York
ENV CONTAINER_USER=labex
ENV CONTAINER_UID=1001

이는 Kickstart 파일의 timezonelang 지시어와 유사합니다. 시스템 로캘, 시간대, 사용자 생성을 위한 변수를 설정하고 있습니다.

3. 패키지 설치:

## Package installation and system configuration
RUN dnf update -y \
  && dnf install -y --allowerasing \
    httpd \
    curl \
    tar \
    gzip \
  && dnf clean all \
  && rm -rf /var/cache/dnf

이 섹션은 Kickstart 의 %packages 섹션과 동일한 기능을 수행합니다. 시스템을 업데이트하고, 충돌을 처리하기 위해 --allowerasing을 사용하여 필요한 패키지를 설치하고, 이미지 크기를 줄이기 위해 패키지 캐시를 정리합니다.

4. 사용자 및 보안 구성:

## Create non-root user for security
RUN useradd -u ${CONTAINER_UID} -m -s /bin/bash ${CONTAINER_USER} \
  && echo "${CONTAINER_USER}:labex" | chpasswd

## Configure Apache for container environment
RUN sed -i 's/Listen 80/Listen 8080/' /etc/httpd/conf/httpd.conf \
  && chown -R ${CONTAINER_USER}:${CONTAINER_USER} /var/log/httpd /var/run/httpd

이는 Kickstart 의 user 지시어 및 설치 후 구성과 유사합니다. 보안을 위해 비 루트 사용자를 생성하고, 컨테이너 환경에 적합하도록 Apache 를 포트 8080 에서 실행하도록 구성합니다.

5. 시작 구성:

## Create startup script
RUN echo '#!/bin/bash' > /start.sh \
  && echo 'echo "RHEL Container started on $(date)" > /var/www/html/index.html' >> /start.sh \
  && echo 'echo "<h1>RHEL 9 Container</h1><p>Deployed via automated configuration</p>" >> /var/www/html/index.html' >> /start.sh \
  && echo 'exec /usr/sbin/httpd -D FOREGROUND' >> /start.sh \
  && chmod +x /start.sh

## Switch to non-root user
USER ${CONTAINER_USER}

## Expose port and define startup
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:8080/ || exit 1

CMD ["/start.sh"]

이 마지막 섹션은 Kickstart 의 %post 섹션 및 서비스 구성과 같습니다. 시작 스크립트를 생성하고, 비 루트 사용자로 전환하고, 웹 서비스 포트를 노출하고, 상태 검사를 정의하고, 컨테이너의 시작 명령을 지정합니다.

새 Dockerfile 이 올바르게 생성되었는지 확인합니다.

cat rhel9-automated.dockerfile

기존 Kickstart 자동화 개념이 최신 컨테이너 기반 RHEL 배포로 어떻게 변환되는지 보여주는 전체 Dockerfile 내용을 볼 수 있습니다.

컨테이너 구성 검증 및 이미지 빌드

이 단계에서는 사용자 지정 Dockerfile 의 유효성을 검사하고 RHEL 컨테이너 이미지를 빌드합니다. 이 프로세스는 ksvalidator를 사용하여 Kickstart 파일의 유효성을 검사하는 것과 유사하지만, 빌드 프로세스 중에 Docker 의 내장된 유효성 검사를 사용합니다. Docker 는 구문을 확인하고 각 명령을 실행하려고 시도하여 문제에 대한 즉각적인 피드백을 제공합니다.

먼저, Dockerfile 이 있는 프로젝트 디렉토리에 있는지 확인합니다.

cd ~/project

빌드하기 전에 Dockerfile 구조를 검사하여 기본적인 구문 검사를 수행해 보겠습니다. Docker 는 빌드하지 않고 기본 구문의 유효성을 검사하는 방법을 제공합니다.

docker build --no-cache --progress=plain -f rhel9-automated.dockerfile -t rhel9-test:validation . --target ""

그러나 가장 효과적인 유효성 검사는 실제로 이미지를 빌드하는 것입니다. 구문 오류 또는 명령 관련 문제가 있는 경우 Docker 는 빌드 프로세스 중에 이를 보고합니다. 기본 UBI9 이미지에 존재하는 curlcurl-minimal 간의 패키지 충돌을 처리하기 위해 dnf install과 함께 --allowerasing 플래그를 사용합니다.

docker build -t rhel9-automated:latest -f rhel9-automated.dockerfile .

빌드 프로세스의 각 단계를 보여주는 출력을 볼 수 있습니다.

[+] Building 45.2s (12/12) FINISHED
 => [internal] load build definition from rhel9-automated.dockerfile
 => => transferring dockerfile: 1.23kB
 => [internal] load .dockerignore
 => => transferring context: 2B
 => [internal] load metadata for docker.io/redhat/ubi9:latest
 => [1/8] FROM docker.io/redhat/ubi9:latest@sha256:...
 => [2/8] RUN dnf update -y &&     dnf install -y --allowerasing         httpd         curl         tar         gzip &&     dnf clean all &&     rm -rf /var/cache/dnf
 => [3/8] RUN useradd -u 1001 -m -s /bin/bash labex &&     echo "labex:labex" | chpasswd
 => [4/8] RUN sed -i 's/Listen 80/Listen 8080/' /etc/httpd/conf/httpd.conf &&     chown -R labex:labex /var/log/httpd /var/run/httpd
 => [5/8] RUN echo '#!/bin/bash' > /start.sh &&     echo 'echo "RHEL Container started on $(date)" > /var/www/html/index.html' >> /start.sh &&     echo 'echo "<h1>RHEL 9 Container</h1><p>Deployed via automated configuration</p>" >> /var/www/html/index.html' >> /start.sh &&     echo 'exec /usr/sbin/httpd -D FOREGROUND' >> /start.sh &&     chmod +x /start.sh
 => [6/8] USER labex
 => exporting to image
 => => exporting layers
 => => writing image sha256:a1b2c3d4e5f6...
 => => naming to docker.io/library/rhel9-automated:latest

빌드가 성공적으로 완료되면 Dockerfile 구문이 올바르고 모든 명령이 제대로 실행되었음을 의미합니다. 빌드 프로세스 중에 로캘 설정 및 구독 관리에 대한 몇 가지 경고 메시지가 표시될 수 있습니다. 이는 UBI 컨테이너에 일반적이며 기능에 영향을 미치지 않습니다.

이미지가 생성되었는지 확인합니다.

docker images rhel9-automated

새로 빌드된 이미지를 볼 수 있습니다.

REPOSITORY       TAG       IMAGE ID       CREATED          SIZE
rhel9-automated  latest    a1b2c3d4e5f6   2 minutes ago    280MB

이제 컨테이너가 예상대로 작동하는지 테스트해 보겠습니다. 분리된 모드에서 컨테이너를 실행합니다.

docker run -d --name rhel9-test -p 8080:8080 rhel9-automated:latest

컨테이너가 실행 중인지 확인합니다.

docker ps

목록에 컨테이너가 표시됩니다.

CONTAINER ID   IMAGE                     COMMAND      CREATED         STATUS         PORTS                    NAMES
a1b2c3d4e5f6   rhel9-automated:latest   "/start.sh"  30 seconds ago  Up 30 seconds  0.0.0.0:8080->8080/tcp   rhel9-test

컨테이너에 요청을 보내 웹 서비스를 테스트합니다.

curl http://localhost:8080

자동화된 RHEL 컨테이너의 HTML 출력을 볼 수 있습니다.

RHEL Container started on Wed Jul 22 14:30:15 UTC 2024
<h1>RHEL 9 Container</h1><p>Deployed via automated configuration</p>

마지막으로, 테스트 컨테이너를 중지하고 제거하여 정리합니다.

docker stop rhel9-test
docker rm rhel9-test

RHEL 컨테이너 구성이 성공적으로 유효성을 검사하고 테스트되었으며, 자동화된 배포 기능을 보여줍니다.

자동 배포 스크립트 생성

이 단계에서는 RHEL 컨테이너를 일관되고 반복적으로 배포하는 방법을 보여주는 자동화 스크립트를 생성합니다. 이 스크립트는 VM 자동화를 위해 Kickstart 파일을 사용하는 것과 동일한 역할을 하지만, 컨테이너화된 RHEL 배포에 맞게 조정되었습니다. 이 스크립트는 이미지 빌드, 컨테이너 배포 및 기본적인 상태 검사를 처리합니다.

먼저, 프로젝트 디렉토리에 있는지 확인합니다.

cd ~/project

Kickstart 및 virt-install을 사용하여 달성할 수 있는 자동화 기능을 모방하는 배포 자동화 스크립트를 생성합니다.

nano deploy-rhel-container.sh

포괄적인 배포 스크립트를 생성하려면 다음 내용을 추가합니다.

#!/bin/bash

## RHEL 컨테이너 자동 배포 스크립트
## 이 스크립트는 컨테이너 기반 RHEL 배포 자동화를 시연합니다.
## VM용 Kickstart 자동화와 유사하지만 컨테이너용입니다.

set -e ## 오류 발생 시 종료

## 구성 변수
IMAGE_NAME="rhel9-automated"
IMAGE_TAG="latest"
CONTAINER_NAME="rhel9-production"
HOST_PORT="8080"
CONTAINER_PORT="8080"
DOCKERFILE="rhel9-automated.dockerfile"

## 출력용 색상 코드
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' ## 색상 없음

## 색상 출력을 인쇄하는 함수
print_status() {
  echo -e "${BLUE}[INFO]${NC} $1"
}

print_success() {
  echo -e "${GREEN}[SUCCESS]${NC} $1"
}

print_warning() {
  echo -e "${YELLOW}[WARNING]${NC} $1"
}

print_error() {
  echo -e "${RED}[ERROR]${NC} $1"
}

## Docker가 실행 중인지 확인하는 함수
check_docker() {
  print_status "Docker 가용성 확인..."
  if ! docker info > /dev/null 2>&1; then
    print_error "Docker가 실행 중이거나 액세스할 수 없습니다."
    exit 1
  fi
  print_success "Docker를 사용할 수 있습니다."
}

## 이미지를 빌드하는 함수
build_image() {
  print_status "RHEL 컨테이너 이미지 빌드..."
  if [ ! -f "$DOCKERFILE" ]; then
    print_error "Dockerfile '$DOCKERFILE'을(를) 찾을 수 없습니다."
    exit 1
  fi

  docker build -t "${IMAGE_NAME}:${IMAGE_TAG}" -f "$DOCKERFILE" .
  print_success "이미지 '${IMAGE_NAME}:${IMAGE_TAG}'가 성공적으로 빌드되었습니다."
}

## 기존 컨테이너를 중지하고 제거하는 함수
cleanup_existing() {
  print_status "기존 컨테이너 확인..."
  if docker ps -a | grep -q "$CONTAINER_NAME"; then
    print_warning "기존 컨테이너 '$CONTAINER_NAME'을(를) 중지하고 제거합니다."
    docker stop "$CONTAINER_NAME" > /dev/null 2>&1 || true
    docker rm "$CONTAINER_NAME" > /dev/null 2>&1 || true
  fi
}

## 컨테이너를 배포하는 함수
deploy_container() {
  print_status "RHEL 컨테이너 배포..."
  docker run -d \
    --name "$CONTAINER_NAME" \
    -p "${HOST_PORT}:${CONTAINER_PORT}" \
    --restart unless-stopped \
    "${IMAGE_NAME}:${IMAGE_TAG}"

  print_success "컨테이너 '$CONTAINER_NAME'이(가) 성공적으로 배포되었습니다."
}

## 배포를 확인하는 함수
verify_deployment() {
  print_status "컨테이너 배포 확인..."

  ## 컨테이너가 시작될 때까지 대기
  sleep 5

  ## 컨테이너가 실행 중인지 확인
  if ! docker ps | grep -q "$CONTAINER_NAME"; then
    print_error "컨테이너가 실행 중이 아닙니다."
    docker logs "$CONTAINER_NAME"
    exit 1
  fi

  ## 웹 서비스가 응답하는지 확인
  print_status "웹 서비스 테스트..."
  for i in {1..10}; do
    if curl -s "http://localhost:${HOST_PORT}" > /dev/null; then
      print_success "웹 서비스가 응답합니다."
      break
    fi
    if [ $i -eq 10 ]; then
      print_error "10번 시도 후에도 웹 서비스가 응답하지 않습니다."
      exit 1
    fi
    sleep 2
  done
}

## 배포 정보를 표시하는 함수
show_deployment_info() {
  print_success "=== RHEL 컨테이너 배포 완료 ==="
  echo "컨테이너 이름: $CONTAINER_NAME"
  echo "이미지: ${IMAGE_NAME}:${IMAGE_TAG}"
  echo "포트 매핑: ${HOST_PORT}:${CONTAINER_PORT}"
  echo "액세스 URL: http://localhost:${HOST_PORT}"
  echo ""
  print_status "컨테이너 상태:"
  docker ps | grep "$CONTAINER_NAME"
  echo ""
  print_status "샘플 내용:"
  curl -s "http://localhost:${HOST_PORT}" | head -2
}

## 주 배포 프로세스
main() {
  echo "=== RHEL 컨테이너 자동 배포 ==="
  echo "이 스크립트는 RHEL 컨테이너 배포를 자동화합니다."
  echo "기존 설치를 위한 Kickstart 자동화와 유사합니다."
  echo ""

  check_docker
  build_image
  cleanup_existing
  deploy_container
  verify_deployment
  show_deployment_info

  print_success "자동화된 RHEL 컨테이너 배포가 성공적으로 완료되었습니다!"
}

## 스크립트 인수 처리
case "${1:-deploy}" in
  "deploy" | "")
    main
    ;;
  "cleanup")
    print_status "배포 정리..."
    cleanup_existing
    docker rmi "${IMAGE_NAME}:${IMAGE_TAG}" 2> /dev/null || true
    print_success "정리가 완료되었습니다."
    ;;
  "status")
    docker ps | grep "$CONTAINER_NAME" || print_warning "컨테이너가 실행 중이 아님"
    ;;
  *)
    echo "사용법: $0 [deploy|cleanup|status]"
    echo "  deploy  - RHEL 컨테이너를 빌드하고 배포합니다(기본값)."
    echo "  cleanup - 컨테이너를 중지하고 이미지를 제거합니다."
    echo "  status  - 컨테이너 상태를 표시합니다."
    exit 1
    ;;
esac

파일을 저장하고 nano 를 종료합니다 (Ctrl+X, 다음 Y, 다음 Enter).

배포 스크립트 구조 이해

스크립트를 실행하기 전에 이 자동화 스크립트가 어떻게 작동하는지 이해해 보겠습니다. 이 섹션에서는 각 구성 요소에 대한 자세한 설명을 제공하여 초보자가 셸 스크립팅 및 컨테이너 자동화 개념을 더 쉽게 이해할 수 있도록 합니다.

스크립트 헤더 및 오류 처리

#!/bin/bash
set -e ## 오류 발생 시 종료
  • #!/bin/bash: 이것은 "shebang"이라고 불리며, 시스템에 이 스크립트를 실행하기 위해 Bash 셸을 사용하도록 지시합니다.
  • set -e: 이 명령은 명령이 실패하면 스크립트가 즉시 종료되도록 하여 잠재적으로 손상된 상태로 계속 진행하는 대신 첫 번째 오류에서 스크립트가 중지되도록 합니다.

구성 변수

## 구성 변수
IMAGE_NAME="rhel9-automated"
IMAGE_TAG="latest"
CONTAINER_NAME="rhel9-production"
HOST_PORT="8080"
CONTAINER_PORT="8080"
DOCKERFILE="rhel9-automated.dockerfile"

이러한 변수는 배포에 대한 모든 주요 매개변수를 정의합니다. 이러한 변수를 맨 위에 배치하면 스크립트 논리를 변경하지 않고도 배포 구성을 쉽게 수정할 수 있습니다. 이는 Kickstart 파일이 구성 매개변수를 사용하는 방식과 유사합니다.

사용자 친화적인 출력 시스템

## 출력용 색상 코드
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' ## 색상 없음

## 색상 출력을 인쇄하는 함수
print_status() {
  echo -e "${BLUE}[INFO]${NC} $1"
}

이는 색상 출력을 사용하여 전문적인 로깅 시스템을 생성합니다.

  • \033[0;31m: 색상에 대한 ANSI 이스케이프 코드 (31 = 빨간색, 32 = 녹색 등)
  • echo -e: -e 플래그는 색상에 대한 백슬래시 이스케이프의 해석을 활성화합니다.
  • $1: 함수에 전달된 첫 번째 인수를 참조합니다.

핵심 배포 기능

1. Docker 환경 확인

check_docker() {
  print_status "Docker 가용성 확인..."
  if ! docker info > /dev/null 2>&1; then
    print_error "Docker가 실행 중이거나 액세스할 수 없습니다."
    exit 1
  fi
  print_success "Docker를 사용할 수 있습니다."
}
  • docker info > /dev/null 2>&1: docker info를 실행하고 출력 (>) 과 오류 (2>&1) 를 모두 /dev/null로 리디렉션합니다 (폐기).
  • !: 결과를 부정합니다. docker info가 실패하면 (0 이 아닌 값을 반환) 조건이 참이 됩니다.
  • 이는 기존 VM 배포에서 가상화가 가능한지 확인하는 것과 같습니다.

2. 이미지 빌드 기능

build_image() {
  print_status "RHEL 컨테이너 이미지 빌드..."
  if [ ! -f "$DOCKERFILE" ]; then
    print_error "Dockerfile '$DOCKERFILE'을(를) 찾을 수 없습니다."
    exit 1
  fi

  docker build -t "${IMAGE_NAME}:${IMAGE_TAG}" -f "$DOCKERFILE" .
  print_success "이미지 '${IMAGE_NAME}:${IMAGE_TAG}'가 성공적으로 빌드되었습니다."
}
  • [ ! -f "$DOCKERFILE" ]: Dockerfile 이 존재하지 않는지 테스트합니다 (!는 부정을 나타내고, -f는 파일 존재 여부를 테스트합니다).
  • docker build -t: 태그 (이름:버전) 가 있는 컨테이너 이미지를 생성합니다.
  • 이는 ISO 미디어에서 기존 설치 프로세스를 대체합니다.

3. 정리 기능

cleanup_existing() {
  print_status "기존 컨테이너 확인..."
  if docker ps -a | grep -q "$CONTAINER_NAME"; then
    print_warning "기존 컨테이너 '$CONTAINER_NAME'을(를) 중지하고 제거합니다."
    docker stop "$CONTAINER_NAME" > /dev/null 2>&1 || true
    docker rm "$CONTAINER_NAME" > /dev/null 2>&1 || true
  fi
}
  • docker ps -a | grep -q: 모든 컨테이너를 나열하고 컨테이너 이름을 조용히 검색합니다.
  • || true: 컨테이너가 존재하지 않더라도 명령이 항상 성공하도록 합니다 (0 반환).
  • 이는 기존 배포와의 충돌을 방지합니다.

4. 컨테이너 배포

deploy_container() {
  print_status "RHEL 컨테이너 배포..."
  docker run -d \
    --name "$CONTAINER_NAME" \
    -p "${HOST_PORT}:${CONTAINER_PORT}" \
    --restart unless-stopped \
    "${IMAGE_NAME}:${IMAGE_TAG}"

  print_success "컨테이너 '$CONTAINER_NAME'이(가) 성공적으로 배포되었습니다."
}
  • -d: 분리 모드 (백그라운드) 에서 컨테이너를 실행합니다.
  • -p "${HOST_PORT}:${CONTAINER_PORT}": 호스트 포트를 컨테이너 포트에 매핑합니다.
  • --restart unless-stopped: 컨테이너가 예기치 않게 중지되면 자동으로 다시 시작합니다 (수동 중지 제외).
  • \: 여러 줄 명령에 대한 줄 연속 문자

5. 상태 확인

verify_deployment() {
  print_status "컨테이너 배포 확인..."

  ## 컨테이너가 시작될 때까지 대기
  sleep 5

  ## 컨테이너가 실행 중인지 확인
  if ! docker ps | grep -q "$CONTAINER_NAME"; then
    print_error "컨테이너가 실행 중이 아닙니다."
    docker logs "$CONTAINER_NAME"
    exit 1
  fi

  ## 웹 서비스가 응답하는지 확인
  print_status "웹 서비스 테스트..."
  for i in {1..10}; do
    if curl -s "http://localhost:${HOST_PORT}" > /dev/null; then
      print_success "웹 서비스가 응답합니다."
      break
    fi
    if [ $i -eq 10 ]; then
      print_error "10번 시도 후에도 웹 서비스가 응답하지 않습니다."
      exit 1
    fi
    sleep 2
  done
}
  • {1..10}: Bash 중괄호 확장 - 1, 2, 3... 10 시퀀스를 생성합니다.
  • curl -s: 무음 모드 HTTP 요청
  • break: 서비스가 응답하면 루프를 조기에 종료합니다.
  • 이는 시간 초과와 함께 재시도 메커니즘을 구현합니다.

명령줄 인터페이스

case "${1:-deploy}" in
  "deploy" | "")
    main
    ;;
  "cleanup")
    print_status "배포 정리..."
    cleanup_existing
    docker rmi "${IMAGE_NAME}:${IMAGE_TAG}" 2> /dev/null || true
    print_success "정리가 완료되었습니다."
    ;;
  "status")
    docker ps | grep "$CONTAINER_NAME" || print_warning "컨테이너가 실행 중이 아님"
    ;;
  *)
    echo "사용법: $0 [deploy|cleanup|status]"
    exit 1
    ;;
esac
  • ${1:-deploy}: 매개변수 확장 - $1(첫 번째 인수) 또는 "deploy"를 기본값으로 사용합니다.
  • case 문: 다른 언어의 switch/case와 유사합니다.
  • ;;: 각 case 분기를 종료합니다.
  • $0: 스크립트 자체의 이름을 참조합니다.

이는 시스템 관리자가 배포, 유지 관리 및 모니터링에 다양한 도구를 사용하는 방식과 유사하게 여러 작업에 사용할 수 있는 다목적 스크립트를 생성합니다.

스크립트를 실행 가능하게 만듭니다.

chmod +x deploy-rhel-container.sh

이제 자동화된 배포 스크립트를 실행하여 전체 자동화 프로세스를 확인합니다.

./deploy-rhel-container.sh

전체 배포 프로세스를 보여주는 출력을 볼 수 있습니다.

=== RHEL 컨테이너 자동 배포 ===
이 스크립트는 RHEL 컨테이너 배포를 자동화합니다.
기존 설치를 위한 Kickstart 자동화와 유사합니다.

[INFO] Docker 가용성 확인...
[SUCCESS] Docker를 사용할 수 있습니다.
[INFO] RHEL 컨테이너 이미지 빌드...
[SUCCESS] 이미지 'rhel9-automated:latest'가 성공적으로 빌드되었습니다.
[INFO] 기존 컨테이너 확인...
[INFO] RHEL 컨테이너 배포...
[SUCCESS] 컨테이너 'rhel9-production'이(가) 성공적으로 배포되었습니다.
[INFO] 컨테이너 배포 확인...
[INFO] 웹 서비스 테스트...
[SUCCESS] 웹 서비스가 응답합니다.
[SUCCESS] === RHEL 컨테이너 배포 완료 ===
컨테이너 이름: rhel9-production
이미지: rhel9-automated:latest
포트 매핑: 8080:8080
액세스 URL: http://localhost:8080

다양한 스크립트 옵션을 테스트합니다.

./deploy-rhel-container.sh status

스크립트 실행 단계별 안내

스크립트를 실행하면 다음 시퀀스가 자동으로 실행됩니다.

1. 환경 유효성 검사 단계

스크립트는 먼저 Docker 를 사용할 수 있고 액세스할 수 있는지 확인합니다. 컨테이너 배포에는 작동하는 Docker 환경이 필요하므로 VM 배포에 작동하는 하이퍼바이저가 필요한 것과 유사합니다.

2. 이미지 빌드 단계

스크립트는 Dockerfile 에서 새 컨테이너 이미지를 빌드합니다. 이 프로세스는 다음과 같습니다.

  • rhel9-automated.dockerfile을 읽습니다.
  • 이미 존재하지 않는 경우 기본 UBI9 이미지를 다운로드합니다.
  • Dockerfile 의 각 명령을 실행합니다.
  • rhel9-automated:latest로 태그된 새 이미지를 생성합니다.

3. 정리 단계

배포하기 전에 스크립트는 동일한 이름을 가진 기존 컨테이너가 있는지 확인하고 제거합니다. 이는 이름 충돌 없이 깨끗한 배포를 보장합니다.

4. 배포 단계

스크립트는 다음을 사용하여 새 컨테이너를 생성하고 시작합니다.

  • 분리 모드: 컨테이너가 백그라운드에서 실행됩니다.
  • 포트 매핑: 호스트 포트 8080 이 컨테이너 포트 8080 에 매핑됩니다.
  • 다시 시작 정책: 컨테이너가 예기치 않게 중지되면 자동으로 다시 시작됩니다.
  • 명명된 컨테이너: 쉬운 식별 및 관리

5. 확인 단계

스크립트는 성공적인 배포를 보장하기 위해 상태 검사를 수행합니다.

  • 컨테이너 상태 확인: 컨테이너가 실행 중인지 확인합니다.
  • 서비스 가용성 확인: HTTP 서비스 응답을 테스트합니다.
  • 재시도 메커니즘: 2 초 간격으로 최대 10 번 시도합니다.
  • 자동 오류 감지: 확인에 실패하면 오류와 함께 종료됩니다.

6. 정보 표시 단계

마지막으로 스크립트는 컨테이너 세부 정보, 액세스 URL 및 샘플 콘텐츠를 포함한 포괄적인 배포 정보를 표시합니다.

실제 사용 예

이 스크립트를 다양한 방식으로 사용할 수 있습니다.

정상적인 배포:

./deploy-rhel-container.sh
## 또는 명시적으로
./deploy-rhel-container.sh deploy

배포 상태 확인:

./deploy-rhel-container.sh status

리소스 정리:

./deploy-rhel-container.sh cleanup

스크립트 도움말 보기:

./deploy-rhel-container.sh help

기존 방법보다 유리한 점

이 자동화 방식은 기존 Kickstart + VM 배포에 비해 몇 가지 장점을 제공합니다.

  1. 속도: 컨테이너 시작은 일반적으로 VM 부팅보다 10-100 배 빠릅니다.
  2. 리소스 효율성: 컨테이너는 호스트 커널을 공유하여 메모리와 CPU 를 덜 사용합니다.
  3. 일관성: 동일한 컨테이너가 서로 다른 환경에서 동일하게 실행됩니다.
  4. 확장성: 여러 인스턴스를 쉽게 생성하거나 수평적으로 확장할 수 있습니다.
  5. 이식성: Docker 가 설치된 모든 시스템에서 실행할 수 있습니다.
  6. 버전 관리: 컨테이너 이미지를 버전 관리하고 레지스트리에 저장할 수 있습니다.

이 자동화 스크립트는 최신 컨테이너 기반 RHEL 배포가 기존 Kickstart 기반 VM 설치와 동일한 수준의 자동화 및 일관성을 달성할 수 있음을 보여주지만, 더 빠른 배포, 더 나은 리소스 활용, 최신 클라우드 환경에서 더 쉬운 확정과 같은 컨테이너화의 추가적인 이점을 제공합니다.

요약

이 Lab 에서는 Docker 컨테이너와 Red Hat Universal Base Images (UBI) 를 사용하여 Red Hat Enterprise Linux (RHEL) 9 배포를 자동화하는 최신 접근 방식을 살펴보았습니다. 기존 RHEL 배포가 Kickstart 파일과 가상 머신에 의존했던 반면, 최신 클라우드 네이티브 환경에서는 redhat/ubi9와 같은 UBI 이미지를 통해 컨테이너화된 RHEL 을 점점 더 많이 사용한다는 것을 알게 되었습니다.

시스템 구성, 패키지 설치, 사용자 관리 및 서비스 구성을 정의하는 사용자 지정 Dockerfile 을 생성하여 기존 Kickstart 개념을 컨테이너 자동화로 변환하는 연습을 했습니다. Kickstart 파일에 ksvalidator를 사용하는 대신, Docker 의 빌드 프로세스를 통해 컨테이너 구성을 검증하는 방법을 배웠으며, 이는 구문 및 실행 오류에 대한 즉각적인 피드백을 제공합니다.

마지막으로, VM 자동화를 위해 Kickstart 파일과 함께 virt-install을 사용하는 것과 유사하게, 엔드 투 엔드 컨테이너 배포를 시연하는 포괄적인 자동화 스크립트를 생성했습니다. 이 접근 방식은 기존 방법과 동일한 수준의 자동화 및 일관성을 제공하는 동시에 컨테이너화의 이점 (더 빠른 배포, 더 나은 리소스 활용, 이식성 및 최신 클라우드 환경에서 더 쉬운 확장) 을 제공합니다.