도커 (Docker)
도커 (Docker)
도커(Docker)는 컨테이너 기반의 오픈소스 가상화 플랫폼입니다. 컨테이너는 애플리케이션과 그에 필요한 모든 의존성, 라이브러리, 바이너리 등을 하나의 패키지로 묶어서 실행하는 기술입니다. 도커를 사용하면 애플리케이션을 빠르고 일관되게 배포하고 실행할 수 있습니다.
도커의 주요 특징 및 장점은 다음과 같습니다:
- 이식성: 애플리케이션과 모든 의존성이 컨테이너 내에 포함되기 때문에, 다양한 환경에서 같은 동작을 보장합니다. 예를 들어, 로컬 환경에서 작동하는 컨테이너는 개발, 테스트, 프로덕션 환경에서도 동일하게 작동합니다.
- 경량성: 컨테이너는 가상 머신과 달리 전체 운영 체제를 포함하지 않기 때문에 크기가 작고 부팅 시간이 빠릅니다. 여러 컨테이너는 같은 호스트에서 독립적으로 실행될 수 있습니다.
- 버전 관리 및 재사용성: 도커 이미지는 버전 관리가 가능하며, 이미지를 기반으로 여러 컨테이너를 실행할 수 있습니다. 또한, 도커 허브와 같은 저장소를 통해 이미지를 공유하고 재사용할 수 있습니다.
- 빠른 배포: 이미지를 기반으로 컨테이너를 빠르게 시작하고 복제할 수 있습니다.
- 격리성: 각 컨테이너는 독립적인 환경에서 실행되므로, 애플리케이션 간의 충돌이나 의존성 문제를 피할 수 있습니다.
도커는 개발에서 운영까지의 전체 라이프 사이클에서 사용될 수 있으며, CI/CD 파이프라인의 일부로 통합되기도 합니다. 도커의 이러한 특징들은 개발자와 운영 팀 모두에게 효율성과 안정성을 제공합니다.
도커 주요한 명령어와 옵션
도커를 사용하면서 자주 사용되는 명령어와 그 주요 옵션들은 다음과 같습니다:
- 도커 이미지 관련 명령어:
- docker pull <이미지 이름>: Docker Hub나 다른 레지스트리에서 이미지를 가져옵니다.
- docker build -t <이미지 이름>:<태그> .: Dockerfile을 기반으로 이미지를 빌드합니다.
- t: 빌드된 이미지의 이름과 태그를 지정합니다.
- docker images: 로컬에 있는 모든 도커 이미지를 나열합니다.
- docker rmi <이미지 이름>: 특정 이미지를 삭제합니다.
- 도커 컨테이너 실행 및 관리 명령어:
- docker run <옵션> <이미지 이름>: 이미지를 기반으로 컨테이너를 생성하고 실행합니다.
- d: 백그라운드 모드에서 컨테이너를 실행합니다.
- p <호스트 포트>:<컨테이너 포트>: 호스트와 컨테이너의 포트를 매핑합니다.
- v <호스트 디렉토리>:<컨테이너 디렉토리>: 볼륨을 마운트하여 호스트와 컨테이너 간의 파일 공유를 설정합니다.
- -name: 컨테이너에 이름을 지정합니다.
- docker ps: 실행 중인 컨테이너를 나열합니다.
- a: 모든 컨테이너를 나열합니다(실행 중인 것과 종료된 것 모두).
- docker stop <컨테이너 이름 또는 ID>: 컨테이너를 정지합니다.
- docker start <컨테이너 이름 또는 ID>: 정지된 컨테이너를 다시 시작합니다.
- docker rm <컨테이너 이름 또는 ID>: 컨테이너를 삭제합니다.
- docker logs <컨테이너 이름 또는 ID>: 컨테이너의 로그를 출력합니다.
- docker run <옵션> <이미지 이름>: 이미지를 기반으로 컨테이너를 생성하고 실행합니다.
- 도커 네트워크 및 볼륨 관련 명령어:
- docker network ls: 도커의 네트워크 목록을 보여줍니다.
- docker volume ls: 도커의 볼륨 목록을 보여줍니다.
- 도커 시스템 관련 명령어:
- docker info: 도커의 시스템 정보를 출력합니다.
- docker system prune: 사용하지 않는 도커 리소스(컨테이너, 네트워크, 볼륨, 이미지)를 삭제합니다.
이 목록은 도커의 기본적인 명령어와 옵션들을 나열한 것이며, 실제로 도커는 이보다 훨씬 다양한 기능과 옵션을 제공합니다. 필요에 따라 도커의 공식 문서나 docker <명령어> --help를 통해 더욱 상세한 정보와 사용 방법을 확인할 수 있습니다.
도커 이미지가 용량이 작은 이유
도커(Docker) 이미지가 용량이 작은 이유는 여러 가지입니다. 이에 대해 상세하게 살펴보겠습니다:
- 레이어 기반 시스템: 도커는 이미지를 여러 레이어로 구성합니다. 새로운 이미지를 만들 때 기존의 이미지 레이어 위에 새로운 레이어를 추가하는 방식으로 동작하므로, 중복된 데이터 없이 필요한 변경 사항만 저장합니다. 이런 방식으로 이미지의 용량을 최소화합니다.
- 최소한의 OS: 대부분의 도커 이미지는 최소한의 운영 체제 컴포넌트만을 포함합니다. 예를 들면, 전체 운영 체제를 설치하지 않고 필요한 라이브러리와 응용 프로그램만을 포함한 'Alpine Linux'와 같은 경량화된 기반 이미지를 사용할 수 있습니다.
- 특정 목적에 최적화: 도커 이미지는 특정 목적을 위해 최적화되어 있습니다. 예를 들어, Node.js 애플리케이션을 위한 이미지는 Node.js 런타임과 관련된 라이브러리만 포함하므로 이미지의 용량을 줄일 수 있습니다.
- 불필요한 파일 제거: 이미지를 작성할 때, 빌드 중간 과정에서 생긴 임시 파일이나 캐시 파일과 같은 불필요한 파일들을 제거하는 것이 일반적입니다. 이러한 방법으로도 이미지의 크기를 줄일 수 있습니다.
- 밀집된 파일 시스템: 도커는 AUFS, Overlay2 등의 밀집된 파일 시스템을 사용하여 여러 레이어를 하나의 파일 시스템처럼 보이게 합니다. 이러한 파일 시스템은 공간 효율성을 높이며, 불필요한 공간 낭비를 방지합니다.
- 도커 이미지 최적화 도구: 여러 최적화 도구들이 개발되어 있어, 이미지의 크기를 더욱 줄일 수 있습니다. 예를 들면, docker-slim 같은 도구를 사용하여 이미지의 크기를 축소할 수 있습니다.
도커 이미지의 크기를 최소화하는 것은 배포 시간을 줄이고, 저장 공간을 절약하며, 보안 위험을 감소시키는 등의 이점이 있습니다. 따라서 많은 개발자와 운영자들이 이미지 크기를 줄이기 위한 다양한 전략과 최적화 기법을 사용합니다.
외부에서 도커 컨테이너로 접속하는 명령어와 옵션
외부에서 도커 컨테이너로 접속하기 위해서는 주로 두 가지 상황을 고려할 수 있습니다:
- 컨테이너 내의 애플리케이션 서비스에 접속하기: 이를 위해서는 docker run 명령어를 사용할 때 포트 매핑 옵션을 사용해야 합니다. 포트 매핑을 사용하면 호스트 시스템의 특정 포트와 컨테이너의 특정 포트를 연결할 수 있습니다.
- p <호스트 포트>:<컨테이너 포트>: 호스트와 컨테이너의 포트를 매핑합니다.
- docker run -d -p 8080:80 nginx
- 컨테이너의 셸에 직접 접속하기: docker exec 명령어를 사용하여 실행 중인 컨테이너의 셸 또는 특정 명령어에 접속할 수 있습니다.
- docker exec -it <컨테이너 이름 또는 ID> /bin/bash (또는 /bin/sh 또는 해당 컨테이너에서 사용 가능한 셸)
- i: 대화식 모드(표준 입력을 열어둔 채로 유지)
- t: TTY 모드(터미널을 할당)
- docker exec -it mycontainer /bin/bash
이러한 명령어와 옵션을 사용하여 도커 컨테이너에 원격에서 접속할 수 있습니다.
도커 컨테이너 정지 정리 명령어
도커 컨테이너를 정지하고 정리하는데 사용되는 주요 명령어는 다음과 같습니다:
- 컨테이너 정지:
- docker stop <컨테이너 이름 또는 ID>: 특정 컨테이너를 정지합니다.
- docker stop $(docker ps -q): 실행 중인 모든 컨테이너를 정지합니다.
- 컨테이너 삭제:
- docker rm <컨테이너 이름 또는 ID>: 특정 컨테이너를 삭제합니다. 컨테이너가 실행 중이면 삭제되지 않습니다.
- docker rm $(docker ps -aq): 모든 컨테이너(실행 중인 것과 정지된 것 모두)를 삭제합니다. 실행 중인 컨테이너는 삭제되지 않습니다.
- 컨테이너 정지 및 삭제:
- docker rm -f <컨테이너 이름 또는 ID>: 특정 컨테이너를 강제로 정지하고 삭제합니다.
- docker rm -f $(docker ps -aq): 모든 컨테이너를 강제로 정지하고 삭제합니다.
- 사용하지 않는 도커 리소스 정리:
- docker system prune: 사용하지 않는 컨테이너, 네트워크, 볼륨, 빌드 캐시 등의 도커 리소스를 삭제합니다.
- a: 사용하지 않는 이미지도 모두 삭제합니다.
- -volumes: 사용하지 않는 볼륨도 삭제합니다.
- docker system prune: 사용하지 않는 컨테이너, 네트워크, 볼륨, 빌드 캐시 등의 도커 리소스를 삭제합니다.
- 사용하지 않는 도커 이미지 정리:
- docker rmi $(docker images -q -f "dangling=true"): <사용하지 않는(불필요한) 도커 이미지를 삭제합니다.
위의 명령어들은 도커 환경을 정리하고 불필요한 리소스를 제거하는 데 도움이 됩니다. 그러나 항상 주의하여 사용해야 합니다. 특히 프로덕션 환경에서는 중요한 데이터가 삭제되지 않도록 주의해야 합니다.
도커 정지를 id로 할 때 앞자리 몇개만 적어서 하는 것도 가
네, 맞습니다. 도커의 명령어에서 컨테이너 ID나 이미지 ID를 지정할 때, ID의 전체 길이를 사용할 필요는 없습니다. ID의 앞쪽 몇 개의 문자만으로도 해당 리소스를 고유하게 식별할 수 있기 때문에 일부만 사용하여 명령어를 실행할 수 있습니다.
예를 들어, docker ps로 컨테이너 목록을 확인했을 때 아래와 같이 출력된다면:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a123456789ab nginx "nginx -g daemon off;" 3 days ago Up 3 days 80/tcp hopeful_shirley
a123456789ab라는 ID의 컨테이너를 정지하려면 다음 중 하나의 명령어를 사용할 수 있습니다:
docker stop a123456789ab
또는
docker stop a123
단, 주의해야 할 점은 ID의 앞부분만 사용할 경우 그 부분이 여러 리소스에 걸쳐 중복되지 않아야 합니다. 중복되는 경우, 도커는 명령어 실행에 실패하며 에러 메시지를 출력합니다.
명령어 들에서 옵션에서 -- 와 - 의 차이
명령어에서 사용되는 --와 -는 다른 의미와 용도를 가집니다. 일반적으로 Unix 및 Linux 기반의 명령어 툴에서 다음과 같은 규칙이 적용됩니다:
- `` (하이픈 한 개):
- 단축 옵션을 나타냅니다.
- 대부분 한 문자로 되어 있습니다.
- 여러 단축 옵션을 연결하여 사용할 수 있습니다. 예: ls -l (디렉토리의 목록을 긴 형식으로 출력), tar -xzf (tarball을 압축 해제)
- - (하이픈 두 개):
- 긴 형식의 옵션을 나타냅니다.
- 대부분 명확한 키워드나 문구로 구성되어 있어, 해당 옵션이 하는 일을 직관적으로 이해하기 쉽습니다. 예: docker run --name mycontainer (컨테이너에 "mycontainer"라는 이름을 지정하여 실행)
또한, --는 명령어에서 옵션의 끝을 나타내는데 사용될 수도 있습니다. 이 경우, 그 뒤에 나오는 항목들은 옵션으로 해석되지 않고 인자로만 해석됩니다. 이러한 사용 방식은 특히 인자 중 하나가 -로 시작하는 경우 유용합니다.
예시:
command --option1 --option2 -- -option3 arg1 arg2
여기서 -option3은 옵션이 아닌 일반 인자로 해석됩니다.
요약하면, -와 --는 명령어 툴의 옵션을 지정하는 방법이며, 각각 단축 옵션과 긴 형식의 옵션을 나타냅니다.
컨테이너 정지 확인
컨테이너가 현재 정지 상태인지 확인하려면 docker ps 명령어를 사용하면 됩니다. 이 명령어는 실행 중인 컨테이너의 목록을 보여줍니다. 정지된 컨테이너를 확인하려면 추가 옵션을 사용해야 합니다.
- 실행 중인 컨테이너만 확인:
- docker ps
- 모든 컨테이너(실행 중인 것과 정지된 것 모두) 확인:
- docker ps -a
docker ps -a 명령어를 사용하면 상태(Status) 열에서 각 컨테이너의 상태를 확인할 수 있습니다. 여기서 "Exited" 상태는 해당 컨테이너가 정지된 상태임을 나타냅니다.
정지된 컨테이너의 목록만 확인하려면 docker ps와 grep 명령어를 함께 사용할 수도 있습니다:
docker ps -a | grep Exited
이 명령어는 정지된 모든 컨테이너의 목록을 출력합니다.
컨테이너 삭제 확인
도커 컨테이너를 삭제한 후에 그 삭제를 확인하려면, 해당 컨테이너가 목록에서 사라졌는지 확인해야 합니다.
- 삭제하려는 컨테이너의 ID나 이름을 기록합니다: 예를 들어 컨테이너의 ID가 a123456789ab라면 이 ID를 기억하거나 복사해둡니다.
- 컨테이너를 삭제합니다:
- docker rm a123456789ab
- 삭제가 잘 되었는지 확인합니다: docker ps -a 명령어를 사용하여 모든 컨테이너의 목록을 확인합니다. 삭제한 컨테이너의 ID나 이름이 목록에서 사라졌다면, 삭제가 성공적으로 수행된 것입니다.위의 명령어를 실행했을 때 아무런 출력이 없다면, 해당 컨테이너는 성공적으로 삭제된 것입니다.
- docker ps -a | grep a123456789ab
이러한 절차를 통해 컨테이너가 성공적으로 삭제되었는지 확인할 수 있습니다.
컨테이너 이미지를 만드는 4가지 방법
도커 컨테이너 이미지를 생성하는 방법은 여러 가지입니다. 아래는 주요한 4가지 방법을 정리한 것입니다:
- Dockerfile을 사용하기:
- Dockerfile은 도커 이미지를 생성하기 위한 명세서입니다. Dockerfile에는 베이스 이미지, 추가 파일, 실행 명령어 등이 포함됩니다.
- Dockerfile을 작성한 후 docker build 명령어를 사용하여 이미지를 생성합니다.
- docker build -t my_image_name:my_tag .
- 컨테이너의 변경사항으로 이미지 생성하기:
- 실행 중인 컨테이너에 변경사항이 있고, 그 변경사항을 포함하는 새로운 이미지를 만들고 싶은 경우 이 방법을 사용합니다.
- 먼저 컨테이너에서 변경사항을 만든 후, docker commit 명령어를 사용하여 이미지를 생성합니다.
- docker commit <container_id_or_name> new_image_name:tag
- 도커 이미지를 Import/Export하기:
- 도커 컨테이너의 파일 시스템을 tar 아카이브로 export한 후, 다른 시스템에서 해당 아카이브를 import하여 이미지를 생성할 수 있습니다.
- Export: docker export <container_id> > container.tar
- Import: docker import - my_new_image_name:tag < container.tar
- 도커 Load/Save 방법으로 이미지 생성하기:
- docker save 명령어를 사용하면 도커 이미지를 tar 아카이브로 저장할 수 있습니다. 이 아카이브는 docker load를 사용하여 다른 도커 시스템에서 이미지로 로드할 수 있습니다.
- Save: docker save -o saved_image.tar my_image_name:my_tag
- Load: docker load -i saved_image.tar
각 방법은 사용 사례나 필요에 따라 선택됩니다. 예를 들어, 컨테이너의 런타임 변경사항을 캡처하려면 docker commit을, 전체 이미지를 다른 시스템으로 전송하려면 docker save/load를 사용하는 것이 좋습니다.
dockerfile이란? 그리고 작성법
Dockerfile은 도커 이미지를 만들기 위한 스크립트나 명세서로 볼 수 있습니다. Dockerfile을 통해 필요한 파일과 설정, 그리고 실행할 명령어를 지정하여 원하는 이미지를 생성할 수 있습니다.
Dockerfile 작성 요소:
- FROM: 사용할 베이스 이미지를 지정합니다.
- FROM ubuntu:20.04
- LABEL: 이미지에 메타데이터를 추가합니다.
- LABEL version="1.0"
- ENV: 환경변수를 설정합니다.
- ENV MY_NAME="John Doe"
- RUN: 이미지 생성 과정에서 실행할 명령어입니다. (예: 패키지 설치)
- RUN apt-get update && apt-get install -y curl
- ADD & COPY: 파일 또는 디렉터리를 이미지로 복사합니다. (COPY가 권장됨)
- COPY ./app /app
- CMD & ENTRYPOINT: 컨테이너 실행 시 기본적으로 실행될 명령어입니다. CMD는 ENTRYPOINT의 기본 인수로 사용될 수 있습니다.
- CMD ["echo", "Hello, World!"]
- WORKDIR: 작업 디렉터리를 설정합니다.
- WORKDIR /app
- EXPOSE: 컨테이너에서 연결을 기다리는 포트를 지정합니다.
- EXPOSE 8080
- VOLUME: 컨테이너에 볼륨을 만듭니다.
- VOLUME /data
Dockerfile 작성 예제:
아래는 간단한 Node.js 애플리케이션을 위한 Dockerfile 예제입니다:
# 베이스 이미지 지정
FROM node:14
# 앱 디렉터리 생성
WORKDIR /usr/src/app
# 앱 의존성 설치
COPY package*.json ./
RUN npm install
# 앱 소스 추가
COPY . .
# 포트 지정
EXPOSE 8080
# 명령어 실행
CMD [ "node", "server.js" ]
이미지 빌드하기:
Dockerfile을 작성한 후에는 docker build 명령어를 사용하여 이미지를 빌드할 수 있습니다.
docker build -t my_image_name .
여기서 -t는 이미지의 이름과 태그를 지정하는 데 사용되며, 마지막의 .은 Dockerfile이 현재 디렉터리에 있음을 가리킵니다.
이러한 방식으로 Dockerfile을 작성하고 빌드하면, 원하는 환경과 설정을 반영하는 도커 이미지를 생성할 수 있습니다.
도커 컨테이너의 IP표시법과 실제 IP
도커 컨테이너에 할당된 IP 주소를 확인하려면, docker inspect 명령어를 사용하면 됩니다.
도커 컨테이너의 IP 주소 확인하기:
- docker inspect를 사용하는 방법:이 명령어는 해당 컨테이너의 모든 정보를 JSON 형식으로 출력하는데, 그 중에서 IP 주소 부분만을 필터링하여 표시합니다.
- docker inspect <container_name_or_id> | grep IPAddress
- docker inspect의 출력을 제어하는 방법: docker inspect는 f 또는 -format 옵션을 사용하여 출력을 템플릿 형식으로 제어할 수 있습니다. 이를 이용하면 IP 주소만 직접 추출할 수 있습니다:
- docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <container_name_or_id>
실제 IP와의 차이:
- 컨테이너 IP: 도커 컨테이너는 호스트에서 격리된 네트워크 네임스페이스에서 실행됩니다. 이로 인해 컨테이너는 자체 IP 주소를 갖게 됩니다. 위의 명령어로 확인하는 IP는 이 컨테이너의 네트워크 네임스페이스 내에서의 IP 주소입니다.
- 호스트 IP: 호스트 머신의 실제 IP 주소를 말합니다. 이 IP는 외부 네트워크와의 통신에 사용됩니다. 도커 호스트의 실제 IP 주소를 확인하려면 일반적인 IP 확인 명령어(ip a, ifconfig 등)를 사용하면 됩니다.
도커는 컨테이너 간의 네트워킹을 위해 내부적으로 bridge 네트워크를 기본으로 사용합니다. 이 bridge 네트워크를 통해 컨테이너는 도커 호스트와 통신할 수 있으며, 필요한 경우 외부 네트워크와도 통신할 수 있습니다.
도커 컨테이너 용량 줄여서 빌드 하는 법
도커 컨테이너 이미지의 용량을 줄이기 위해서는 여러 방법들이 있습니다. 용량을 줄이는 것은 배포나 저장 시간을 줄여 효율성을 높이는 데 도움이 됩니다. 다음은 몇 가지 주요 방법들을 정리한 것입니다:
- 멀티 스테이지 빌드 사용: 멀티 스테이지 빌드를 사용하면 빌드 도구나 중간 파일들을 최종 이미지에서 제외할 수 있습니다.
- # 첫 번째 스테이지: 빌드 환경 FROM node:14 AS build WORKDIR /app COPY package*.json ./ RUN npm install COPY . . RUN npm run build # 두 번째 스테이지: 실행 환경 FROM node:14-slim WORKDIR /app COPY --from=build /app/dist /app/dist
- 기본 이미지 최적화: slim 태그나 alpine 태그가 붙은 기본 이미지를 사용하면 크기를 줄일 수 있습니다. 예를 들어, node:14-slim이나 node:14-alpine 같은 이미지를 선택합니다.
- 불필요한 파일 제거:
- .dockerignore 파일을 사용하여 불필요한 파일이나 디렉터리를 도커 이미지 빌드에서 제외합니다.
- RUN 명령어에서 생성된 불필요한 파일이나 패키지를 삭제합니다. 예를 들어, apt-get을 사용할 때 -no-install-recommends 옵션을 추가하거나, 빌드 후 apt-get clean을 사용하여 캐시를 지울 수 있습니다.
- 명령어 결합: 도커는 각 RUN, COPY, ADD 명령어마다 새로운 레이어를 생성합니다. 가능한 한 명령어들을 한 줄로 결합하여 레이어 수를 줄입니다.
- RUN apt-get update && apt-get install -y package-name && apt-get clean && rm -rf /var/lib/apt/lists/*
- 도커 이미지 최적화 도구 사용: dive나 docker-slim 같은 도구를 사용하여 이미지를 분석하고 최적화할 수 있습니다.
이러한 방법들을 통해 도커 이미지의 크기를 줄이고, 배포와 운영의 효율성을 높일 수 있습니다.
GCR(Google Container Registry)에서 제공하는 distroless
Google Container Registry(GCR)에서 제공하는 "distroless" 이미지는 운영 체제의 기본적인 도구나 라이브러리만을 포함한 최소한의 이미지입니다. 이러한 distroless 이미지는 필요 없는 컴포넌트를 제거하여 보안 위협을 줄이고, 이미지 크기를 최소화합니다.
distroless의 주요 특징:
- 보안: distroless 이미지는 셸, 패키지 관리자, 또는 다른 편의 도구 없이 실행 환경만 제공합니다. 이로 인해 공격 범위(surface)가 줄어들어 보안성이 향상됩니다.
- 크기: 불필요한 컴포넌트를 포함하지 않기 때문에 이미지 크기가 작습니다.
- 간결함: 애플리케이션과 그에 필요한 라이브러리만 포함되므로 관리 및 디버깅이 더 간결하고 직관적입니다.
사용 방법:
Distroless 이미지는 여러 언어 및 프레임워크에 대한 기본 이미지를 제공합니다. 예를 들어, 자바나 파이썬, 노드JS용 distroless 이미지를 사용할 수 있습니다.
예를 들어, 자바 애플리케이션의 경우:
FROM gcr.io/distroless/java:11
COPY /path/to/your/application.jar /app/application.jar
CMD ["app/application.jar"]
Distroless 이미지를 사용하면, 해당 언어 또는 프레임워크의 런타임만 포함하게 되므로, 이미지가 더 작고 보안적으로 더 강화됩니다.
결론:
Distroless는 클라우드 네이티브 환경에서 애플리케이션을 실행하기 위한 미니멀한 이미지를 제공합니다. 이러한 이미지는 애플리케이션의 보안과 효율성을 향상시키는 데 도움을 줍니다.
멀티 스테이지 빌드 원리와 핵심
멀티 스테이지 빌드는 Dockerfile 내에서 여러 개의 빌드 단계를 정의하고, 각 단계에서 필요한 파일이나 결과물만을 최종 이미지로 복사하는 기능입니다. 이를 통해 불필요한 도구나 중간 파일을 최종 이미지에서 제외할 수 있습니다.
멀티 스테이지 빌드의 원리:
- 단계별 이미지 생성: Dockerfile 내에서 여러 FROM 문을 사용해 여러 개의 이미지를 생성합니다. 각 이미지는 독립적인 레이어와 환경을 갖게 됩니다.
- 단계 간 파일 전송: 한 단계에서 생성된 결과물을 다른 단계의 이미지로 복사할 수 있습니다. 이때 COPY --from=<stage_name_or_number> <source> <destination> 문법을 사용합니다.
- 최종 결과 생성: 마지막 단계에서 필요한 파일이나 디렉터리만을 최종 이미지로 선택하여 복사합니다.
멀티 스테이지 빌드의 핵심:
- 이미지 크기 최소화: 중간 단계에서 사용된 빌드 도구, 라이브러리, 의존성 등을 최종 이미지에서 제외할 수 있어 이미지 크기를 줄일 수 있습니다.
- 보안 강화: 최종 이미지에 불필요한 파일이나 도구를 포함하지 않음으로써 보안 리스크를 줄일 수 있습니다.
- 빌드 최적화: 특정 단계에서 빌드나 테스트 도구를 사용하여 애플리케이션을 컴파일하거나 테스트한 후, 필요한 결과물만 최종 이미지로 전달함으로써 빌드 과정을 최적화 할 수 있습니다.
예시:
# 첫 번째 단계: 빌드 환경 설정
FROM node:14 AS build
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 두 번째 단계: 실행 환경 설정
FROM node:14-slim
WORKDIR /app
# 첫 번째 단계에서 빌드한 결과물을 복사
COPY --from=build /app/dist /app/dist
이 예시에서 첫 번째 단계에서는 Node.js 애플리케이션을 빌드하고, 두 번째 단계에서는 빌드된 결과물만을 최종 이미지에 포함시킵니다. 이로써 최종 이미지 크기가 줄어들고, 빌드 도구나 중간 파일을 포함하지 않게 됩니다.
왜 멀티 스테이지 빌드라고 이름 붙였을까?
멀티 스테이지 빌드는 Docker 이미지 빌드 과정을 여러 단계로 나누는 방법입니다. 각 단계는 독립적인 빌드 컨텍스트와 결과물을 가질 수 있습니다. 주요 목적은 다음과 같습니다:
- 최소한의 이미지 생성: 최종 이미지는 애플리케이션 실행에 꼭 필요한 파일과 의존성만 포함하게 됩니다. 중간 단계에서 사용되는 빌드 도구, 컴파일러, 라이브러리 등은 최종 이미지에서 제외될 수 있습니다.
- 의존성 주입: 중간 단계에서 필요한 라이브러리나 도구를 설치하고 애플리케이션을 빌드한 후, 이 결과물만을 다음 단계로 전달하며, 최종 이미지에는 꼭 필요한 의존성만 주입됩니다.
그럼 "왜 이름을 멀티 스테이지 빌드라고 붙였는지?"에 대한 답변입니다:
"멀티"는 여러 개라는 뜻을 가지며, "스테이지"는 특정한 과정이나 단계를 의미합니다. Docker에서 멀티 스테이지 빌드를 사용하면, 여러 개의 빌드 단계를 통해 하나의 최종 이미지를 생성할 수 있습니다. 각 단계는 FROM 명령어로 시작하여 독립적인 이미지를 형성하며, 이후 단계에서 이전 단계의 결과물을 가져와 사용할 수 있습니다. 따라서 이름에서 "멀티 스테이지"라는 용어가 나타내는 바는 "여러 단계를 거쳐 이미지를 빌드한다"는 의미를 담고 있습니다.
일반 도커 이미지 빌드 과정과 멀티 스테이지 빌드의 과정 차이
물론이죠. 일반적인 도커 이미지 빌드와 멀티 스테이지 빌드 과정의 주요 차이를 설명하면서 각각의 예시를 제공하겠습니다.
1. 일반 도커 이미지 빌드:
Dockerfile 예시:
# 기본 이미지 선택
FROM node:14
# 작업 디렉터리 설정
WORKDIR /app
# 의존성 파일 복사 및 설치
COPY package*.json ./
RUN npm install
# 애플리케이션 코드 복사
COPY . .
# 애플리케이션 빌드 (예: 웹팩을 사용하는 경우)
RUN npm run build
설명:
- 기본 이미지를 선택하고, 해당 이미지 위에 필요한 도구나 라이브러리를 설치합니다.
- 애플리케이션 코드와 의존성을 이미지에 복사한 후, 필요한 빌드나 컴파일 작업을 진행합니다.
- 이 과정에서 빌드 도구, 중간 파일, 라이브러리 등이 모두 최종 이미지에 포함됩니다.
2. 멀티 스테이지 빌드:
Dockerfile 예시:
# 첫 번째 단계 - 빌드
FROM node:14 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 두 번째 단계 - 실행
FROM node:14-slim
WORKDIR /app
# 첫 번째 단계에서 빌드한 결과물을 복사
COPY --from=builder /app/dist /app/dist
설명:
- 첫 번째 단계에서는 기본 이미지를 사용하여 애플리케이션의 빌드 작업을 진행합니다. 여기에는 빌드 도구, 라이브러리, 중간 파일 등이 포함됩니다.
- 두 번째 단계에서는 더 경량화된 이미지를 기반으로 사용하며, 첫 번째 단계에서 빌드된 결과물만을 복사하여 최종 이미지를 생성합니다.
- 결과적으로 최종 이미지는 첫 번째 단계의 중간 파일, 빌드 도구 등을 포함하지 않기 때문에 이미지 크기가 훨씬 작아집니다.
이러한 차이로 인해 멀티 스테이지 빌드는 애플리케이션의 이미지 크기를 줄이고, 보안을 강화하는 데 유용하게 사용됩니다.
첫번째 단계를 공통인데 멀티 스테이지는 첫번재 단계에서 생성한 도커이미지에서 원하는 파일/폴더 부분만 선택적으로 복사해서 그걸 도커 이미지로 만드는 기법
멀티 스테이지 빌드의 핵심은 여러 단계를 거쳐 여러 이미지를 생성하되, 최종 이미지에서는 필요한 파일이나 폴더만 선택적으로 가져오는 것입니다.
첫 번째 단계에서는 빌드 도구, 의존성 라이브러리, 소스 코드 등을 모두 포함하면서 애플리케이션을 빌드합니다. 이 단계에서의 이미지는 모든 빌드 도구와 중간 파일을 포함하므로 크기가 크다는 특징이 있습니다.
그 후, 두 번째 단계에서는 경량화된 베이스 이미지를 사용하면서 첫 번째 단계에서 빌드된 결과물 중 필요한 부분만 선택하여 복사합니다. 이렇게 하면 최종 이미지에는 불필요한 빌드 도구나 중간 파일들이 포함되지 않게 되어 이미지 크기가 훨씬 줄어들게 됩니다.
이러한 멀티 스테이지 빌드 방식을 사용하면 이미지 크기를 최소화하면서도 애플리케이션의 빌드 및 실행에 필요한 모든 파일과 설정을 제공할 수 있습니다.
쿠버네티스에서 컨테이너 이미지 구동
쿠버네티스(Kubernetes)에서 컨테이너 이미지를 구동하려면 여러 리소스와 오브젝트를 사용해 설정과 배포를 합니다. 여기서는 간단한 Pod를 사용하여 컨테이너 이미지를 구동하는 방법을 설명하겠습니다.
1. 쿠버네티스 설정 준비
쿠버네티스 클러스터와 kubectl CLI 도구가 설치 및 설정되어 있어야 합니다.
2. Pod 생성 및 이미지 구동
Pod 정의 파일 예시 (my-pod.yaml):
apiVersion: v1
kind: Pod
metadata:
name: my-pod
labels:
app: my-app
spec:
containers:
- name: my-container
image: [YOUR_IMAGE_NAME]:[YOUR_TAG]
이 YAML 파일에서 [YOUR_IMAGE_NAME]은 사용할 도커 이미지 이름을, [YOUR_TAG]는 해당 이미지의 태그를 나타냅니다.
Pod 생성 명령어:
kubectl apply -f my-pod.yaml
3. Pod 상태 확인
kubectl get pods
4. 로그 확인
특정 Pod의 로그를 확인하려면 다음 명령어를 사용합니다.
kubectl logs my-pod
5. Pod 내부에 접속
Pod 내의 컨테이너에 접속하려면 다음 명령어를 사용합니다.
kubectl exec -it my-pod -- /bin/sh
(컨테이너 내부에 /bin/sh나 /bin/bash가 설치되어 있어야 합니다.)
6. Pod 삭제
kubectl delete pod my-pod
쿠버네티스는 Pod 외에도 Deployment, Service, ConfigMap, Secret 등 다양한 리소스와 오브젝트를 제공합니다. 이를 통해 복잡한 애플리케이션 배포, 스케일링, 롤링 업데이트, 서비스 디스커버리 등의 기능을 활용할 수 있습니다.
Pod 정의 파일와 작성법 -k8s 관련
쿠버네티스의 Pod는 하나 이상의 컨테이너를 함께 실행하는 기본 배포 단위입니다. Pod를 생성하려면 Pod에 대한 정의를 YAML 또는 JSON 형식으로 제공해야 합니다. 여기서는 Pod의 YAML 정의 파일 작성 방법에 초점을 맞춰 설명하겠습니다.
Pod 정의 파일 기본 구조
apiVersion: v1
kind: Pod
metadata:
name: pod-name
labels:
key1: value1
spec:
containers:
- name: container-name
image: container-image
ports:
- containerPort: port-number
각 섹션 설명
- apiVersion: 쿠버네티스 API의 버전을 나타냅니다. Pod는 v1 API 버전을 사용합니다.
- kind: 쿠버네티스 오브젝트의 종류를 나타냅니다. 여기서는 Pod입니다.
- metadata: 오브젝트의 메타데이터를 정의합니다.
- name: Pod의 이름입니다.
- labels: Key-value 쌍으로 구성된 레이블입니다. 다른 쿠버네티스 리소스에서 이 Pod를 찾을 때 사용됩니다.
- spec: Pod의 사양을 정의합니다.
- containers: Pod에 포함된 컨테이너 목록입니다.
- name: 컨테이너의 이름입니다.
- image: 사용할 컨테이너 이미지의 이름입니다.
- ports: 컨테이너가 리스닝하는 네트워크 포트 목록입니다.
- containers: Pod에 포함된 컨테이너 목록입니다.
예시
간단한 nginx 컨테이너를 실행하는 Pod의 정의 예시는 다음과 같습니다.
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
Pod 생성
YAML 파일을 작성한 후, kubectl 명령어를 사용하여 Pod를 생성할 수 있습니다.
kubectl apply -f [YOUR_POD_DEFINITION_FILE].yaml
추가 설정
Pod 정의에는 환경 변수, 볼륨 마운트, 리소스 제한, 리스타트 정책, 라이브니스/레디니스 프로브 등 많은 추가 설정이 가능합니다. 필요에 따라 이러한 설정을 추가하여 Pod의 동작을 더욱 세밀하게 제어할 수 있습니다.
이렇게 정의된 Pod는 클러스터 내에서 실행되며, 필요에 따라 다양한 리소스와 상호작용하거나 연계할 수 있습니다.
레지스트리 구성
컨테이너 레지스트리는 컨테이너 이미지를 저장하고 배포하는 서비스입니다. Docker Hub가 가장 잘 알려진 레지스트리의 예이지만, 많은 조직들이 개인적이거나 업무상의 이유로 자체 레지스트리를 운영하기도 합니다.
자체 Docker 레지스트리를 설정하려면 다음과 같은 단계를 따르면 됩니다:
1. Docker Registry 이미지 실행
Docker Hub에서 제공하는 공식 registry 이미지를 사용하여 Docker 레지스트리 컨테이너를 실행합니다.
docker run -d -p 5000:5000 --restart=always --name registry registry:2
이 명령어는 Docker 레지스트리를 포트 5000에서 실행합니다.
2. 이미지 태그 및 푸시
로컬에 있는 이미지를 레지스트리에 푸시하기 전에 해당 레지스트리 주소로 이미지를 태그해야 합니다.
docker tag [YOUR_IMAGE_NAME]:[YOUR_TAG] localhost:5000/[YOUR_IMAGE_NAME]:[YOUR_TAG]
docker push localhost:5000/[YOUR_IMAGE_NAME]:[YOUR_TAG]
3. 레지스트리에서 이미지 풀
docker pull localhost:5000/[YOUR_IMAGE_NAME]:[YOUR_TAG]
4. 보안
기본적으로 레지스트리는 보안(HTTPS)을 사용하지 않습니다. 실제 환경에서는 HTTPS 설정, 기본 인증, 외부 인증 서비스 (예: LDAP) 연동 등의 보안 조치가 필요합니다.
5. 저장소 정리
레지스트리에 저장된 오래된 이미지나 사용하지 않는 태그를 정리하려면 레지스트리 컨테이너 내에서 가비지 컬렉션을 실행할 수 있습니다.
docker exec registry bin/registry garbage-collect /etc/docker/registry/config.yml
6. Docker Registry 설정 파일
상세한 구성이나 보안 설정, 저장소 백엔드 변경 등의 추가 설정이 필요한 경우, Docker Registry에 대한 설정 파일을 작성하고 컨테이너 실행 시에 이를 마운트할 수 있습니다.
이러한 절차는 간단한 Docker 레지스트리의 설정을 나타냅니다. 실제 운영 환경에서는 보안, 스토리지 최적화, 로깅 및 모니터링, 백업 등의 추가적인 고려 사항이 있습니다. 또한, 다양한 클라우드 제공자 (예: AWS ECR, Google GCR, Azure ACR)에서도 호스팅된 컨테이너 레지스트리 서비스를 제공하므로, 이를 활용하는 것도 좋은 방법입니다.
도커 허브 repo에 내 로컬 이미지 푸쉬하는 방법
로컬의 Docker 이미지를 외부의 Docker Hub에 푸시하는 과정은 여러 단계로 이루어집니다. 아래는 그 단계별로 설명한 내용입니다:
1. Docker Hub 계정 준비
- Docker Hub에 가입하여 계정을 생성합니다.
- 로그인할 계정 이름을 알고 있어야 합니다.
2. 로컬에서 Docker에 로그인
터미널 또는 명령 프롬프트에서 다음 명령어를 사용하여 Docker Hub에 로그인합니다:
docker login
- 사용자 이름과 비밀번호를 입력하여 로그인합니다.
3. 로컬 이미지를 Docker Hub 리포지토리 이름으로 태그 지정
docker tag [로컬이미지명]:[태그] [DockerHub_사용자명]/[리포지토리명]:[태그]
예를 들면:
docker tag mylocalimage:latest myusername/myimage:latest
4. 태그 지정된 이미지를 Docker Hub에 푸시
docker push [DockerHub_사용자명]/[리포지토리명]:[태그]
예를 들면:
docker push myusername/myimage:latest
5. Docker Hub 웹 사이트에서 푸시 상태 확인
Docker Hub 계정으로 로그인한 후, 해당 리포지토리로 이동하여 푸시된 이미지를 확인할 수 있습니다.
이 과정을 완료하면 로컬의 Docker 이미지가 Docker Hub에 푸시되고, 다른 위치에서도 해당 이미지를 풀하여 사용할 수 있게 됩니다.
출처: 컨테이너 인프라 환경 구축을 위한 쿠버네티스/도커
사설 도커 레지스트리 만들기
사설 Docker 레지스트리를 만들어, 조직 내부나 개인적인 환경에서 Docker 이미지를 안전하게 관리할 수 있습니다. 아래는 사설 Docker 레지스트리를 만드는 방법에 대해 설명하겠습니다.
1. Docker Registry 컨테이너 실행
Docker Hub에서 제공하는 공식 registry 이미지를 사용하여 Docker 레지스트리 컨테이너를 실행할 수 있습니다.
docker run -d -p 5000:5000 --name myregistry registry:2
이렇게 하면 포트 5000에서 Docker 레지스트리가 실행됩니다.
2. 이미지 태그 및 푸시
로컬에 있는 이미지를 사설 레지스트리에 푸시하기 전에 해당 레지스트리 주소로 이미지를 태그해야 합니다.
docker tag [YOUR_IMAGE_NAME]:[YOUR_TAG] localhost:5000/[YOUR_IMAGE_NAME]:[YOUR_TAG]
docker push localhost:5000/[YOUR_IMAGE_NAME]:[YOUR_TAG]
3. 사설 레지스트리에서 이미지 풀
docker pull localhost:5000/[YOUR_IMAGE_NAME]:[YOUR_TAG]
4. 보안 설정
기본적으로 Docker 레지스트리는 보안(HTTPS)을 사용하지 않습니다. 실제 환경에서는 HTTPS로 레지스트리를 설정하거나 인증 메커니즘을 추가하는 것이 좋습니다.
5. 저장소 정리
오래된 이미지나 불필요한 태그를 정리하려면 레지스트리 컨테이너에서 가비지 컬렉션을 실행할 수 있습니다.
docker exec myregistry bin/registry garbage-collect /etc/docker/registry/config.yml
6. 고급 설정 및 보안
실제 운영 환경에서는 보안, 스토리지 백엔드 설정, 로깅 및 모니터링, 백업 등의 추가적인 설정과 조치가 필요합니다. 예를 들어, TLS 인증서를 사용하여 HTTPS를 설정하거나 기본 인증 또는 OAuth와 같은 인증 메커니즘을 추가로 구성할 수 있습니다.
사설 Docker 레지스트리는 내부적으로 Docker 이미지를 관리하고 배포하는 데 유용한 방법이지만, 관리 및 보안 측면에서 주의가 필요합니다. 필요한 설정과 보안 조치를 철저히 검토하고 적용하여 안전하게 운영하는 것이 중요합니다.
create-registry.sh 파일과 TLS.CSR파일
Docker private 레지스트리(registry)를 설정하면서 TLS 인증서를 사용하여 보안 연결을 구성하는 과정에 관련된 것으로 보입니다.
아래는 사설 Docker 레지스트리를 설정하고 TLS 보안을 적용하기 위한 간략한 가이드입니다.
1. TLS 인증서 생성 -(AI 답변)(참고만)
먼저, OpenSSL을 사용하여 자체 서명된 인증서와 개인 키를 생성합니다.
openssl req -newkey rsa:4096 -nodes -sha256 -keyout domain.key -out tls.csr
이 명령어는 tls.csr (Certificate Signing Request) 파일과 domain.key 개인 키를 생성합니다.
그 다음, 인증서를 생성합니다.
openssl x509 -req -days 365 -in tls.csr -signkey domain.key -out domain.crt
이 명령어는 tls.csr를 사용하여 domain.crt 인증서를 생성합니다.
tls.csr - 책
tls.csr
[req]
distinguished_name = private_registry_cert_req
x509_extensions = v3_req
prompt = no
[private_registry_cert_req]
C = KR
ST = SEOUL
L = SEOUL
O = gilbut
OU = Book_k8sInfra
CN = 192.168.1.10
[v3_req]
keyUsage = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.0 = m-k8s
IP.0 = 192.168.1.10
tls.csr는 Certificate Signing Request (CSR)을 생성하기 위한 OpenSSL 설정 파일로 보입니다. 여기서 명시된 설정을 사용하여 CSR을 생성하면, 이를 기반으로 SSL/TLS 인증서를 발급받을 수 있습니다.
설정 파일의 주요 부분들에 대한 간략한 설명은 다음과 같습니다:
- [req]: CSR 생성에 대한 기본 설정을 나타냅니다.
- distinguished_name: Distinguished Name(DN) 섹션을 지정합니다.
- x509_extensions: X.509 v3 인증서 확장을 지정합니다.
- prompt: DN 값을 직접 입력하지 않도록 설정합니다 (no).
- [private_registry_cert_req]: Distinguished Name(DN) 섹션의 필드를 나타냅니다.
- C: 국가 코드 (KR은 대한민국을 의미)
- ST: 주 또는 지역 이름
- L: 지역 이름
- O: 조직 이름
- OU: 조직 단위 이름
- CN: Common Name, 주로 서버의 FQDN 또는 IP 주소를 사용
- [v3_req]: X.509 v3 확장에 대한 설정을 나타냅니다.
- keyUsage: 키의 사용 방법을 지정합니다.
- extendedKeyUsage: 키의 확장된 사용 방법을 지정합니다. 여기서는 서버 인증(serverAuth)만 명시되어 있습니다.
- subjectAltName: 대체 이름을 지정하는 섹션을 가리킵니다.
- [alt_names]: 대체 이름(Subject Alternative Name, SAN)을 지정합니다. 여기서는 DNS 이름과 IP 주소를 지정하였습니다.
해당 설정 파일을 사용하여 CSR을 생성하려면 다음과 같은 명령을 실행할 수 있습니다:
openssl req -new -key your_private_key.key -out request.csr -config tls.csr
여기서 your_private_key.key는 키 파일의 경로를 의미하며, 실제 키 파일 경로로 대체해야 합니다.
create-registry.sh - 책
create-registry.sh
#!/usr/bin/env bash
certs=/etc/docker/certs.d/192.168.1.10:8443
mkdir /registry-image
mkdir /etc/docker/certs
mkdir -p $certs
openssl req -x509 -config $(dirname "$0")/tls.csr -nodes -newkey rsa:4096 \\
-keyout tls.key -out tls.crt -days 365 -extensions v3_req
yum install sshpass -y
for i in {1..3}
do
sshpass -p vagrant ssh -o StrictHostKeyChecking=no root@192.168.1.10$i mkdir -p
$certs
sshpass -p vagrant scp tls.crt 192.168.1.10$i:$certs
done
cp tls.crt $certs
mv tls.* /etc/docker/certs
docker run -d \\
--restart=always \\
--name registry \\
-v /etc/docker/certs:/docker-in-certs:ro \\
-v /registry-image:/var/lib/registry \\
-e REGISTRY_HTTP_ADDR=0.0.0.0:443 \\
-e REGISTRY_HTTP_TLS_CERTIFICATE=/docker-in-certs/tls.crt \\
-e REGISTRY_HTTP_TLS_KEY=/docker-in-certs/tls.key \\
-p 8443:443 \\
registry:2
create-registry.sh는 사설 Docker 레지스트리를 설정하고 실행하는 스크립트입니다.
이 스크립트는 여러 단계를 수행하며, 각 단계에 대한 설명은 다음과 같습니다:
- 환경 변수 및 디렉토리 설정:
- certs 변수에는 TLS 인증서가 저장될 경로를 지정합니다.
- /registry-image와 /etc/docker/certs 디렉토리를 생성합니다.
- $certs에 해당하는 디렉토리도 생성합니다.
- OpenSSL로 인증서 생성:
- openssl 명령어를 사용하여 tls.csr 설정 파일을 기반으로 자체 서명 인증서(self-signed certificate)와 키를 생성합니다.
- 이 인증서는 1년 동안 유효하며, RSA 알고리즘과 4096비트 키로 생성됩니다.
- sshpass 설치 및 원격 서버에 인증서 배포:
- sshpass 패키지를 설치합니다. 이는 비밀번호를 전달하여 ssh 명령어를 실행하는 데 사용됩니다.
- for문을 사용하여 3개의 원격 서버(192.168.1.101, 192.168.1.102, 192.168.1.103)에 $certs 디렉토리를 생성하고, 생성된 tls.crt 인증서를 복사합니다.
- 인증서를 로컬 시스템에 복사 및 이동:
- tls.crt 인증서를 $certs 디렉토리에 복사합니다.
- tls.key와 tls.crt를 /etc/docker/certs로 이동합니다.
- Docker 레지스트리 컨테이너 실행:
- Docker의 registry:2 이미지를 기반으로 사설 Docker 레지스트리 컨테이너를 실행합니다.
- 컨테이너가 항상 실행되도록 -restart=always 옵션을 사용합니다.
- 인증서 및 키를 마운트하고, 레지스트리의 데이터를 /registry-image에 저장합니다.
- 레지스트리는 443 포트로 구동되며, 호스트 시스템의 8443 포트와 연결됩니다.
이 스크립트를 실행하면, 지정된 IP 주소와 포트(192.168.1.10:8443)에서 사설 Docker 레지스트리가 구동됩니다. 그리고 해당 레지스트리를 사용하기 위해서는 tls.crt 인증서를 각 클라이언트에 설치해야 합니다.
위의 create-registry.sh 와 tls.csr 으로 두 사설 도커 레지스트리 만들기
create-registry.sh와 tls.csr를 사용하여 두 개의 사설 Docker 레지스트리를 생성하는 방법은 기본적으로 스크립트를 조금 수정하는 것입니다. 아래는 간략한 단계를 설명합니다:
- tls.csr 파일 변경:
- 필요한 경우, CN (Common Name) 및 subjectAltName의 IP를 두 번째 레지스트리의 IP 주소로 변경합니다.
- create-registry.sh 스크립트 수정:
- 두 번째 레지스트리에 대한 정보 (예: IP 주소, 포트 번호 등)를 환경 변수로 추가하거나 기존 변수의 값을 변경합니다.
- docker run 명령을 두 번 실행하여 두 개의 레지스트리를 실행합니다. 포트 및 볼륨 마운트 경로를 변경하여 충돌을 방지해야 합니다.
아래는 create-registry.sh 스크립트의 수정된 버전입니다:
#!/usr/bin/env bash
# 첫 번째 레지스트리 정보
certs1=/etc/docker/certs.d/192.168.1.10:8443
mkdir /registry-image1
mkdir -p $certs1
# 두 번째 레지스트리 정보
certs2=/etc/docker/certs.d/192.168.1.11:8444
mkdir /registry-image2
mkdir -p $certs2
# 인증서 생성 (첫 번째 레지스트리)
openssl req -x509 -config $(dirname "$0")/tls.csr -nodes -newkey rsa:4096 \\\\
-keyout tls1.key -out tls1.crt -days 365 -extensions v3_req
# 인증서 생성 (두 번째 레지스트리)
openssl req -x509 -config $(dirname "$0")/tls.csr -nodes -newkey rsa:4096 \\\\
-keyout tls2.key -out tls2.crt -days 365 -extensions v3_req
yum install sshpass -y
# 첫 번째 레지스트리 인증서 배포
for i in {1..3}
do
sshpass -p vagrant ssh -o StrictHostKeyChecking=no root@192.168.1.10$i mkdir -p $certs1
sshpass -p vagrant scp tls1.crt root@192.168.1.10$i:$certs1
done
# 두 번째 레지스트리 인증서 배포
for i in {1..3}
do
sshpass -p vagrant ssh -o StrictHostKeyChecking=no root@192.168.1.10$i mkdir -p $certs2
sshpass -p vagrant scp tls2.crt root@192.168.1.10$i:$certs2
done
cp tls1.crt $certs1
mv tls1.* /etc/docker/certs
cp tls2.crt $certs2
mv tls2.* /etc/docker/certs
# 첫 번째 레지스트리 실행
docker run -d \\\\
--restart=always \\\\
--name registry1 \\\\
-v /etc/docker/certs:/docker-in-certs1:ro \\\\
-v /registry-image1:/var/lib/registry \\\\
-e REGISTRY_HTTP_ADDR=0.0.0.0:443 \\\\
-e REGISTRY_HTTP_TLS_CERTIFICATE=/docker-in-certs1/tls1.crt \\\\
-e REGISTRY_HTTP_TLS_KEY=/docker-in-certs1/tls1.key \\\\
-p 8443:443 \\\\
registry:2
# 두 번째 레지스트리 실행
docker run -d \\\\
--restart=always \\\\
--name registry2 \\\\
-v /etc/docker/certs:/docker-in-certs2:ro \\\\
-v /registry-image2:/var/lib/registry \\\\
-e REGISTRY_HTTP_ADDR=0.0.0.0:443 \\\\
-e REGISTRY_HTTP_TLS_CERTIFICATE=/docker-in-certs2/tls2.crt \\\\
-e REGISTRY_HTTP_TLS_KEY=/docker-in-certs2/tls2.key \\\\
-p 8444:443 \\\\
registry:2
이 스크립트를 실행하면, 192.168.1.10:8443 및 192.168.1.11:8444에서 각각 사설 Docker 레지스트리가 실행됩니다.
2. Docker 레지스트리 실행
Docker 레지스트리를 실행할 때, 위에서 생성한 인증서와 개인 키를 사용합니다.
docker run -d -p 5000:5000 \\\\
--name secure-registry \\\\
-v /path/to/certs:/certs \\\\
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \\\\
-e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \\\\
registry:2
3. create-registry.sh 스크립트
실제 환경에서는 create-registry.sh 스크립트를 작성하여 위의 단계를 자동화할 수 있습니다.
#!/bin/bash
# 인증서 및 키 생성
openssl req -newkey rsa:4096 -nodes -sha256 -keyout domain.key -out tls.csr
openssl x509 -req -days 365 -in tls.csr -signkey domain.key -out domain.crt
# Docker 레지스트리 실행
docker run -d -p 5000:5000 \\\\
--name secure-registry \\\\
-v /path/to/certs:/certs \\\\
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \\\\
-e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \\\\
registry:2
스크립트에 실행 권한을 부여하고 실행합니다:
chmod +x create-registry.sh
./create-registry.sh
이러한 단계를 통해 사설 Docker 레지스트리를 보안된 방식으로 설정할 수 있습니다. 하지만, 자체 서명된 인증서를 사용할 경우 다른 시스템에서 레지스트리에 접근할 때 인증서를 신뢰해야 합니다.
직접 만든 이미지로 컨테이너 구동하기
직접 만든 Docker 이미지로 컨테이너를 구동하는 것은 간단한 작업입니다. 아래는 이미지를 빌드하고 해당 이미지로 컨테이너를 실행하는 기본적인 단계를 설명합니다.
1. Dockerfile 작성
먼저, 이미지를 생성하기 위한 Dockerfile을 작성해야 합니다. 예를 들어, 간단한 Node.js 애플리케이션을 실행하는 이미지를 만들기 위한 Dockerfile은 다음과 같이 작성될 수 있습니다:
# Node.js LTS 버전 이미지를 기반으로 합니다.
FROM node:14
# 작업 디렉토리를 설정합니다.
WORKDIR /app
# 애플리케이션의 종속성을 설치하기 위해 package.json 파일을 복사합니다.
COPY package.json ./
# 애플리케이션의 종속성을 설치합니다.
RUN npm install
# 애플리케이션의 모든 파일을 이미지에 복사합니다.
COPY . .
# 3000 포트를 열어줍니다.
EXPOSE 3000
# 애플리케이션을 실행합니다.
CMD ["npm", "start"]
2. Docker 이미지 빌드
이제 Dockerfile을 사용하여 이미지를 빌드합니다:
docker build -t my-custom-image .
위 명령어는 현재 디렉토리(.)의 Dockerfile을 사용하여 my-custom-image라는 이름의 이미지를 빌드합니다.
3. 컨테이너 구동
빌드된 이미지를 사용하여 컨테이너를 실행합니다:
docker run -d -p 3000:3000 my-custom-image
위 명령어는 my-custom-image 이미지를 기반으로 컨테이너를 백그라운드에서 실행하고, 호스트의 3000 포트와 컨테이너의 3000 포트를 연결합니다.
이제, 웹 브라우저나 다른 HTTP 클라이언트를 사용하여 http://localhost:3000 주소로 애플리케이션에 접근할 수 있습니다.
직접 만든 이미지로 컨테이너 구동하기
사설 Docker 레지스트리에 이미지를 푸시한 후 해당 이미지를 사용하여 컨테이너를 구동하려면 다음 단계를 따르십시오:
- 이미지 태깅: 자신의 로컬에서 생성한 이미지에 대한 태그를 설정해야 합니다. 이 태그는 사설 레지스트리의 주소와 일치해야 합니다.예:
- docker tag myapp:latest 192.168.1.10:8443/myapp:latest
- docker tag [로컬 이미지 이름]:[태그] [사설 레지스트리 주소]/[이미지 이름]:[태그]
- 이미지 푸시: 태그가 지정된 이미지를 사설 Docker 레지스트리에 푸시합니다.예:
- docker push 192.168.1.10:8443/myapp:latest
- docker push [사설 레지스트리 주소]/[이미지 이름]:[태그]
- 컨테이너 구동: 푸시한 이미지를 사용하여 컨테이너를 실행합니다.예:
- docker run -d -p 8080:80 192.168.1.10:8443/myapp:latest
- docker run -d -p [외부 포트]:[컨테이너 내부 포트] [사설 레지스트리 주소]/[이미지 이름]:[태그]
이러한 단계를 완료하면 사설 Docker 레지스트리에 저장된 이미지를 사용하여 컨테이너가 실행됩니다.
참고: 사설 레지스트리에 연결할 때 인증 또는 SSL 관련 문제가 발생하면 Docker 구성을 확인하거나 레지스트리 설정을 검토해야 할 수 있습니다.
도커 허브에 repo 이미지로 구동하는 법
Docker Hub는 Docker 컨테이너 이미지를 저장하는 공개 레지스트리입니다. Docker Hub에서 이미지를 다운로드하여 로컬에서 실행하는 과정은 매우 간단합니다. 아래는 Docker Hub에 호스팅된 이미지를 사용하여 컨테이너를 실행하는 단계입니다:
- 이미지 가져오기 (pull): Docker Hub에서 원하는 이미지를 로컬 시스템에 다운로드합니다. 이것을 "pulling"이라고 합니다.예를 들어, 공식 nginx 이미지의 최신 버전을 가져오려면:
- docker pull nginx:latest
- docker pull [이미지 이름]:[태그]
- 컨테이너 구동: 이미지를 기반으로 새로운 컨테이너 인스턴스를 시작합니다.예를 들어, nginx:latest 이미지를 사용하여 웹 서버를 실행하려면:이렇게 하면, nginx 웹 서버가 로컬의 80번 포트에서 실행됩니다. 웹 브라우저를 열고 http://localhost로 이동하면 nginx 웹 페이지를 볼 수 있습니다.
- docker run -d -p 80:80 nginx:latest
- docker run -d -p [외부 포트]:[컨테이너 내부 포트] [이미지 이름]:[태그]
- 컨테이너 확인: 실행 중인 컨테이너의 목록을 보려면 다음 명령을 사용하십시오:
- docker ps
- 컨테이너 중지 및 제거: 컨테이너를 중지하려면:컨테이너를 삭제하려면:
- docker rm [컨테이너 ID 또는 이름]
- docker stop [컨테이너 ID 또는 이름]
이러한 기본 단계를 사용하여 Docker Hub에서 이미지를 가져와 로컬에서 컨테이너를 실행할 수 있습니다.
빌드한 도커 이미지를 통해 배포된 파드에 셸 접속되지 않는 경우
Docker 이미지를 기반으로 Kubernetes에서 Pod를 배포하고 그 Pod의 셸에 접속하려 할 때 문제가 발생할 수 있습니다. 여러 가지 원인과 그에 따른 해결 방법이 있습니다. 다음은 몇 가지 일반적인 원인과 해결 방법에 대한 정보입니다:
- 파드가 실행 중이지 않는 경우: 먼저 파드의 상태를 확인해야 합니다.만약 파드가 'Pending'이나 'Error' 상태에 있다면, 그 원인을 알아보기 위해 로그를 확인하십시오.
- kubectl describe pod [파드 이름]
- kubectl get pods
- ENTRYPOINT 또는 CMD 지시문 문제: 만약 Docker 이미지의 ENTRYPOINT 또는 CMD가 무한 루프를 실행하지 않고 종료된다면, 파드의 컨테이너는 계속해서 종료될 것입니다. 이 경우, 파드에 셸 접속하기 위해 실행 중인 컨테이너가 없게 됩니다.
- 셸이 포함되지 않은 이미지: 도커 이미지가 매우 최소화된 버전이거나 셸을 포함하지 않는 이미지 (예: distroless 이미지)일 경우, 셸 접속이 불가능합니다.
- kubectl exec 명령의 문제점: 다음과 같은 명령으로 파드에 셸 접속을 시도합니다:만약 /bin/sh가 작동하지 않는다면, 다른 셸을 시도해보십시오. 예를 들면, /bin/bash를 사용해보세요.
- kubectl exec -it [파드 이름] -- /bin/sh
- 보안 정책: 네트워크 정책, 파드 보안 정책 또는 RBAC 설정이 적절하지 않으면 파드 셸 접속에 문제가 발생할 수 있습니다. 관련된 보안 설정을 확인해보십시오.
- 기타 문제점: 파드와 관련된 다른 이슈가 있을 수 있습니다. 파드 로그를 확인하여 문제점을 알아볼 수 있습니다.
- kubectl logs [파드 이름]
상황에 따라 문제의 원인을 파악하고 적절한 조치를 취해야 합니다. 위의 단계는 문제를 해결하는 데 도움을 줄 수 있는 일반적인 접근 방법을 제공합니다.
'[F-Lab 멘토링 학습]' 카테고리의 다른 글
| 분산 캐시(distributed cache) (0) | 2023.09.19 |
|---|---|
| API 게이트웨이 (0) | 2023.09.19 |
| 프래피티 STUDY - 다이나믹 배열, 해시 함수 속성 및 유형 (0) | 2023.09.17 |
| 프래피티 STUDY - 오버로딩과 오버라이딩, Primitive 타입과 Reference 타입 (0) | 2023.09.17 |
| 쿠버네티스 (K8S) (0) | 2023.09.15 |