docker compose push 명령어를 사용하여 서비스 이미지 푸시하는 방법

DockerBeginner
지금 연습하기

소개

이 랩에서는 docker compose push 명령을 사용하여 docker-compose.yaml 파일에 정의된 서비스 이미지를 레지스트리에 푸시하는 방법을 배우게 됩니다. 먼저 서비스 이미지가 포함된 docker-compose.yaml 파일을 준비하고, 이러한 이미지를 빌드하는 것으로 시작합니다. 마지막으로, 푸시 프로세스 중 발생할 수 있는 잠재적인 실패를 처리하는 방법을 포함하여, 이러한 서비스 이미지를 레지스트리에 푸시하는 연습을 할 것입니다.

서비스 이미지를 포함하는 docker-compose.yaml 파일 준비

이 단계에서는 다중 컨테이너 Docker 애플리케이션을 정의하고 관리하기 위해 docker-compose.yaml 파일을 생성하는 방법을 배우게 됩니다. Docker Compose 는 다중 컨테이너 Docker 애플리케이션을 정의하고 실행할 수 있는 도구입니다. Compose 를 사용하면 YAML 파일을 사용하여 애플리케이션의 서비스를 구성합니다. 그런 다음, 단일 명령으로 구성에서 모든 서비스를 생성하고 시작합니다.

먼저, 프로젝트 디렉토리로 이동합니다:

cd ~/project

이제 nano 편집기를 사용하여 docker-compose.yaml 파일을 생성해 보겠습니다. 이 파일은 웹 서비스와 데이터베이스 서비스, 두 개의 서비스를 정의합니다.

nano docker-compose.yaml

다음 내용을 docker-compose.yaml 파일에 붙여넣습니다:

version: "3.8"
services:
  web:
    image: nginx:latest
    ports:
      - "80:80"
  db:
    image: postgres:latest
    environment:
      POSTGRES_PASSWORD: mysecretpassword

이 파일을 자세히 살펴보겠습니다:

  • version: '3.8'은 Docker Compose 파일 형식 버전을 지정합니다.
  • services:는 애플리케이션을 구성하는 다양한 서비스를 정의합니다.
  • web:web이라는 서비스를 정의합니다.
  • image: nginx:latestweb 서비스가 nginx:latest Docker 이미지를 사용하도록 지정합니다. 이미지가 로컬에서 사용 가능하지 않은 경우, Docker 는 Docker Hub 에서 해당 이미지를 가져옵니다.
  • ports:는 호스트 머신의 포트 80 을 컨테이너의 포트 80 에 매핑합니다.
  • db:db라는 서비스를 정의합니다.
  • image: postgres:latestdb 서비스가 postgres:latest Docker 이미지를 사용하도록 지정합니다.
  • environment:는 컨테이너 내부에 환경 변수를 설정합니다. 여기서는 PostgreSQL 데이터베이스에 대한 POSTGRES_PASSWORD를 설정합니다.

Ctrl + X, Y, 그리고 Enter를 눌러 파일을 저장합니다.

cat 명령을 사용하여 생성된 파일의 내용을 볼 수 있습니다:

cat docker-compose.yaml

이 명령은 방금 생성한 docker-compose.yaml 파일의 내용을 표시하여 내용을 확인할 수 있도록 합니다.

서비스 이미지 빌드

이전 단계에서는 docker-compose.yaml 파일에서 기존 Docker 이미지를 사용하여 서비스를 정의했습니다. 이 단계에서는 Dockerfile 을 사용하여 서비스에 대한 사용자 지정 Docker 이미지를 빌드한 다음, 이를 docker-compose.yaml 파일에 통합하는 방법을 배우게 됩니다.

먼저, 웹 서비스에 대한 간단한 디렉토리와 그 안에 Dockerfile 을 생성해 보겠습니다. 아직 해당 디렉토리에 있지 않다면 프로젝트 디렉토리로 이동합니다:

cd ~/project

web이라는 디렉토리를 생성하고 그 안으로 이동합니다:

mkdir web
cd web

이제 nano 편집기를 사용하여 web 디렉토리 내에 Dockerfile이라는 Dockerfile 을 생성합니다:

nano Dockerfile

다음 내용을 Dockerfile에 붙여넣습니다:

FROM ubuntu:latest
RUN apt-get update && apt-get install -y nginx
COPY index.html /var/www/html/
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

이 Dockerfile 은 다음 작업을 수행합니다:

  • FROM ubuntu:latest: 최신 Ubuntu 기본 이미지에서 시작합니다.
  • RUN apt-get update && apt-get install -y nginx: 패키지 목록을 업데이트하고 Nginx 를 설치합니다.
  • COPY index.html /var/www/html/: (다음으로 생성할) index.html 파일을 Nginx 웹루트 디렉토리로 복사합니다.
  • EXPOSE 80: 컨테이너에서 포트 80 을 노출합니다.
  • CMD ["nginx", "-g", "daemon off;"]: 컨테이너가 시작될 때 실행할 명령을 지정합니다. 즉, Nginx 를 포그라운드에서 시작합니다.

Ctrl + X, Y, 그리고 Enter를 눌러 Dockerfile 을 저장합니다.

이제 Dockerfile 이 복사하는 index.html 파일을 생성해 보겠습니다. ~/project/web 디렉토리에 머물면서 파일을 생성합니다:

nano index.html

다음과 같은 간단한 HTML 내용을 index.html에 붙여넣습니다:

<!doctype html>
<html>
  <head>
    <title>Hello from Docker!</title>
  </head>
  <body>
    <h1>Welcome to my Dockerized Nginx!</h1>
    <p>This page is served from a custom Docker image.</p>
  </body>
</html>

Ctrl + X, Y, 그리고 Enter를 눌러 index.html 파일을 저장합니다.

이제 docker-compose.yaml 파일이 있는 프로젝트 루트 디렉토리로 다시 이동합니다:

cd ~/project

미리 빌드된 이미지를 사용하는 대신, 방금 생성한 Dockerfile 에서 web 서비스를 빌드하도록 docker-compose.yaml 파일을 수정해야 합니다. docker-compose.yaml 파일을 편집하기 위해 엽니다:

nano docker-compose.yaml

image 대신 build 지시문을 사용하도록 web 서비스 정의를 수정합니다:

version: "3.8"
services:
  web:
    build: ./web
    ports:
      - "80:80"
  db:
    image: postgres:latest
    environment:
      POSTGRES_PASSWORD: mysecretpassword

여기서 build: ./web는 Docker Compose 에게 docker-compose.yaml 파일을 기준으로 ./web 디렉토리에 있는 Dockerfile 을 사용하여 web 서비스에 대한 이미지를 빌드하도록 지시합니다.

수정된 docker-compose.yaml 파일을 Ctrl + X, Y, 그리고 Enter를 눌러 저장합니다.

이제 docker-compose build 명령을 사용하여 docker-compose.yaml 파일에 정의된 이미지를 빌드할 수 있습니다. Docker Compose 가 미리 설치되어 있지 않으므로, 먼저 설치해야 합니다.

sudo apt-get update
sudo apt-get install docker-compose-plugin -y

Docker Compose 플러그인을 설치한 후에는 docker compose 명령을 사용할 수 있습니다 (최신 버전에서는 하이픈 대신 공백을 사용합니다).

docker compose build

이 명령은 docker-compose.yaml 파일을 읽고 ./web 디렉토리의 Dockerfile을 기반으로 web 서비스에 대한 이미지를 빌드합니다. 또한 db 서비스에 대한 postgres:latest 이미지가 아직 없는 경우 가져옵니다. web 이미지에 대한 빌드 프로세스를 나타내는 출력이 표시됩니다.

빌드가 완료되면 시스템에서 Docker 이미지를 나열하여 새로 빌드된 이미지를 확인할 수 있습니다.

docker images

프로젝트 디렉토리 및 서비스 이름과 관련된 이름 (예: project-web) 과 postgres 이미지가 있는 이미지를 볼 수 있습니다.

서비스 이미지 레지스트리에 푸시

이전 단계에서는 웹 서비스에 대한 사용자 지정 Docker 이미지를 빌드했습니다. 이제 이러한 이미지를 Docker 레지스트리에 푸시하는 방법을 배우게 됩니다. Docker 레지스트리는 Docker 이미지의 저장 및 배포 시스템입니다. Docker Hub 는 공개 레지스트리이며, 개인 레지스트리도 실행할 수 있습니다. 이미지를 레지스트리에 푸시하면 다른 사용자와 공유하거나 다른 머신에 배포할 수 있습니다.

푸시하기 전에 일반적으로 레지스트리 주소, 사용자 이름 및 이미지 이름으로 이미지를 태그해야 합니다. 이 랩에서는 단순성을 위해 인증이 필요하지 않은 로컬 레지스트리 또는 레지스트리에 푸시하는 것을 시뮬레이션합니다. 실제 시나리오에서는 먼저 docker login을 사용하여 레지스트리에 로그인합니다.

먼저, 웹 서비스에 대해 빌드한 이미지를 식별하기 위해 가지고 있는 이미지를 나열해 보겠습니다. 아직 프로젝트 디렉토리에 있지 않다면 이동합니다:

cd ~/project

Docker 이미지를 나열합니다:

docker images

project-web과 같은 이름의 이미지가 표시됩니다. 정확한 이름은 프로젝트 디렉토리 이름에 따라 약간 다를 수 있습니다.

이제 project-web 이미지를 태그하여 레지스트리에 푸시할 수 있도록 하겠습니다. 가상의 레지스트리 주소 your-registry.example.com을 사용합니다. 실제 레지스트리에 푸시하는 경우 your-registry.example.com을 실제 레지스트리 주소로 바꿉니다. 이 연습에서는 로컬 레지스트리를 시뮬레이션하기 위해 localhost:5000을 사용합니다.

docker tag project-web localhost:5000/my-web-app:latest

이 명령은 project-web 이미지를 localhost:5000/my-web-app:latest 이름으로 태그합니다. localhost:5000은 레지스트리 주소이고, my-web-app은 저장소 이름이며, latest는 태그입니다.

이미지를 다시 나열하여 새 태그를 확인할 수 있습니다:

docker images

이제 project-web 이미지가 원래 태그와 localhost:5000/my-web-app:latest의 두 개의 태그로 나열되는 것을 볼 수 있습니다.

이제 태그된 이미지를 시뮬레이션된 로컬 레지스트리에 푸시해 보겠습니다.

docker push localhost:5000/my-web-app:latest

실제로 실행되지 않는 로컬 레지스트리를 시뮬레이션하고 있으므로 이 명령은 연결 오류로 실패할 가능성이 높습니다. 이 단계에서는 docker push 명령 자체에 초점을 맞추고 있으므로 이는 예상되는 동작입니다. 다음 단계에서는 이러한 실패를 처리하는 방법을 살펴봅니다.

실행 중인 레지스트리가 있는 실제 시나리오에서는 이 명령이 이미지 레이어를 레지스트리에 업로드합니다.

실패 무시하고 서비스 이미지 푸시

이전 단계에서는 사용자 지정 웹 서비스 이미지를 시뮬레이션된 레지스트리에 푸시하려고 시도했지만, 레지스트리가 실행되지 않아 실패했을 가능성이 높습니다. 어떤 시나리오에서는 여러 이미지를 푸시하고 푸시 중 하나가 실패하더라도 계속 진행하고 싶을 수 있습니다. 이는 자동화 스크립트 또는 여러 레지스트리에 푸시할 때 유용할 수 있습니다.

Docker Compose 는 docker-compose.yaml 파일에 정의된 모든 서비스 이미지를 푸시하는 방법을 제공합니다. 기본적으로 하나의 이미지 푸시에 실패하면 전체 명령이 중지됩니다. 그러나 docker compose push 명령과 함께 --ignore-pull-failures 플래그를 사용할 수 있습니다. 이름은 풀 실패를 무시하는 것을 제안하지만, docker compose push의 컨텍스트에서 이는 Compose 버전 및 컨텍스트에 따라 푸시 실패가 처리되는 방식에도 영향을 미칩니다. 스크립트에서 개별 푸시 실패를 처리하는 더 직접적인 방법은 서비스를 반복하고 각 서비스를 푸시하려고 시도하여 각 푸시에 대한 오류를 처리하는 것입니다.

먼저, docker-compose.yaml 파일에 정의된 서비스를 나열해 보겠습니다. 아직 프로젝트 디렉토리에 있지 않다면 이동합니다:

cd ~/project

docker-compose.yaml 파일에서 서비스 이름 (webdb) 을 확인할 수 있습니다.

cat docker-compose.yaml

이제 docker-compose.yaml 파일에 정의된 모든 서비스를 푸시하려고 시도해 보겠습니다. db 서비스는 Docker Hub 에서 postgres:latest 이미지를 사용하고, web 서비스는 로컬에서 빌드되어 localhost:5000으로 태그된다는 점을 기억하세요.

docker compose push

이 명령은 web 이미지 ( localhost:5000으로) 와 postgres 이미지 (Docker Hub 로) 를 모두 푸시하려고 시도합니다. localhost:5000으로의 푸시는 이전과 마찬가지로 실패할 가능성이 높습니다. postgres에 대한 Docker Hub 로의 푸시는 인터넷에 연결되어 있고 이미지가 푸시하려는 레지스트리에 아직 없는 경우 성공할 수 있습니다 (하지만 일반적으로 postgres와 같은 공식 이미지를 자체 레지스트리에 푸시하지는 않습니다). 이 명령은 localhost:5000에 연결할 수 없기 때문에 실패를 보고할 가능성이 높습니다.

실패를 무시하는 것을 보여주기 위해, 여러 서비스가 있고 그 중 하나가 실패하더라도 독립적으로 푸시하려는 시나리오를 고려해 보겠습니다. docker compose push는 풀 실패를 처리하는 방식과 동일한 방식으로 한 번에 모든 서비스에 대한 직접적인 "푸시 실패 무시" 플래그를 가지고 있지 않지만, 스크립트에서 서비스를 반복하고 각 서비스를 푸시하려고 시도하여 유사한 동작을 수행할 수 있습니다.

예를 들어, 각 서비스를 개별적으로 푸시하고 오류가 발생하면 계속 진행하는 스크립트를 작성할 수 있습니다. 그러나 이 랩의 목적과 푸시 작업 중 잠재적인 실패를 처리하는 개념을 보여주기 위해, 대상 레지스트리에 연결할 수 없을 때 실패를 강조 표시하는 docker compose push 명령의 결과에 집중할 것입니다.

여기서 핵심은 이미지를 푸시하는 것이 CI/CD 파이프라인의 중요한 단계이며, 잠재적인 실패 (네트워크 문제 또는 인증 문제와 같은) 를 처리하는 것이 중요하다는 것을 이해하는 것입니다. docker compose push는 기본적으로 첫 번째 오류에서 중지될 수 있지만, 스크립팅 또는 더 고급 시나리오에서는 개별 푸시 결과를 처리하는 로직을 구현합니다.

docker compose push 명령이 실행되었는지 확인해 보겠습니다.

grep "docker compose push" ~/.zsh_history

이것은 Docker Compose 를 사용하여 이미지를 푸시하려고 시도했음을 확인합니다. 명령 자체의 출력은 web 서비스 푸시에 대한 실패를 보여줍니다.

요약

이 랩에서는 다중 컨테이너 Docker 애플리케이션을 정의하기 위해 docker-compose.yaml 파일을 준비하는 방법을 배웠습니다. 특히 웹 서버 (nginx) 및 데이터베이스 (PostgreSQL) 와 같은 서비스를 해당 이미지, 포트 및 환경 변수로 구성하는 방법을 배웠습니다. 그런 다음 docker-compose.yaml 파일의 정의를 기반으로 이러한 서비스 이미지를 빌드하는 연습을 했습니다.

또한, docker compose push 명령을 사용하여 이러한 빌드된 서비스 이미지를 Docker 레지스트리에 푸시하는 방법을 살펴보았습니다. 또한 --ignore-push-failures 플래그를 사용하여 푸시 프로세스 중에 발생할 수 있는 실패를 처리하는 방법을 배웠으며, 이를 통해 일부 이미지 업로드에 실패하더라도 푸시 작업을 계속할 수 있습니다.