Docker 시작하기: DevOps 간소화
게시 됨: 2022-03-11고래를 좋아하거나 소프트웨어를 프로덕션에 빠르고 쉽게 지속적으로 제공하는 데 관심이 있다면 이 Docker 입문서를 읽어보시기 바랍니다. 모든 것이 소프트웨어 컨테이너가 IT의 미래임을 나타내는 것 같으므로 컨테이너 고래인 Moby Dock 및 Molly에 대해 간략히 살펴보겠습니다.
친근한 고래 모양의 로고로 표시되는 Docker는 소프트웨어 컨테이너 내부에 애플리케이션 배포를 용이하게 하는 오픈 소스 프로젝트입니다. 기본 기능은 Linux 커널의 리소스 격리 기능에 의해 활성화되지만 그 위에 사용자 친화적인 API를 제공합니다. 첫 번째 버전은 2013년에 출시되었으며 이후 엄청난 인기를 얻었으며 eBay, Spotify, Baidu 등과 같은 많은 대기업에서 널리 사용되고 있습니다. 마지막 자금 조달 라운드에서 Docker는 9,500만 달러라는 막대한 자금을 유치했으며 DevOps 서비스의 필수 요소가 될 예정입니다.
운송 상품 비유
Docker 이면의 철학은 다음과 같은 간단한 비유로 설명할 수 있습니다. 국제 운송 산업에서 상품은 지게차, 트럭, 기차, 크레인 및 선박과 같은 다양한 수단을 통해 운송되어야 합니다. 이러한 상품은 다양한 모양과 크기로 제공되며 설탕 자루, 우유 캔, 식물 등의 보관 요구 사항도 다릅니다. 역사적으로 이는 적재 및 하역을 위해 모든 운송 지점에서 수동 개입에 의존하는 고통스러운 과정이었습니다.
복합 운송 컨테이너의 도입으로 모든 것이 바뀌었습니다. 표준 크기로 제공되고 운송을 염두에 두고 제조되기 때문에 모든 관련 기계는 최소한의 인간 개입으로 이를 처리하도록 설계할 수 있습니다. 밀폐 용기의 또 다른 이점은 민감한 물품의 온도 및 습도와 같은 내부 환경을 보존할 수 있다는 것입니다. 결과적으로 운송 업계는 상품 자체에 대해 걱정하지 않고 A에서 B로 이동하는 데 집중할 수 있습니다.
그리고 여기에서 Docker가 소프트웨어 산업에 유사한 이점을 제공합니다.
가상 머신과 어떻게 다릅니까?
얼핏 보면 가상 머신과 Docker 컨테이너가 비슷해 보일 수 있습니다. 그러나 다음 다이어그램을 보면 주요 차이점이 분명해집니다.
하이퍼바이저와 별개로 가상 머신에서 실행되는 애플리케이션에는 운영 체제의 전체 인스턴스와 지원 라이브러리가 필요합니다. 반면에 컨테이너는 운영 체제를 호스트와 공유합니다. 하이퍼바이저는 컨테이너의 수명 주기를 관리한다는 점에서 컨테이너 엔진(이미지에서 Docker로 표시됨)과 비슷합니다. 중요한 차이점은 컨테이너 내부에서 실행되는 프로세스는 호스트의 기본 프로세스와 동일하며 하이퍼바이저 실행과 관련된 오버헤드가 발생하지 않는다는 것입니다. 또한 애플리케이션은 라이브러리를 재사용하고 컨테이너 간에 데이터를 공유할 수 있습니다.
두 기술의 강점이 다르기 때문에 가상 머신과 컨테이너를 결합한 시스템을 찾는 것이 일반적입니다. 완벽한 예는 Docker 설치 섹션에 설명된 Boot2Docker라는 도구입니다.
도커 아키텍처
아키텍처 다이어그램의 맨 위에 레지스트리가 있습니다. 기본적으로 기본 레지스트리는 공개 및 공식 이미지를 호스팅하는 Docker Hub입니다. 원하는 경우 조직에서 개인 레지스트리를 호스팅할 수도 있습니다.
오른쪽에는 이미지와 컨테이너가 있습니다. 이미지는 레지스트리에서 명시적으로( docker pull imageName
) 다운로드하거나 컨테이너를 시작할 때 암시적으로 다운로드할 수 있습니다. 이미지가 다운로드되면 로컬로 캐시됩니다.
컨테이너는 이미지의 인스턴스이며 살아있는 것입니다. 동일한 이미지를 기반으로 실행 중인 여러 컨테이너가 있을 수 있습니다.
중앙에는 컨테이너 생성, 실행 및 모니터링을 담당하는 Docker 데몬이 있습니다. 또한 이미지 빌드 및 저장을 처리합니다. 마지막으로 왼쪽에는 Docker 클라이언트가 있습니다. HTTP를 통해 데몬과 통신합니다. Unix 소켓은 동일한 시스템에 있을 때 사용되지만 HTTP 기반 API를 통해 원격 관리가 가능합니다.
도커 설치
최신 지침은 항상 공식 문서를 참조해야 합니다.
Docker는 기본적으로 Linux에서 실행되므로 대상 배포에 따라 sudo apt-get install docker.io
만큼 쉬울 수 있습니다. 자세한 내용은 설명서를 참조하십시오. 일반적으로 Linux에서는 Docker 명령 앞에 sudo
를 추가하지만 명확성을 위해 이 기사에서는 생략합니다.
Docker 데몬은 Linux 관련 커널 기능을 사용하므로 Mac OS 또는 Windows에서 기본적으로 Docker를 실행할 수 없습니다. 대신 Boot2Docker라는 응용 프로그램을 설치해야 합니다. 응용 프로그램은 VirtualBox 가상 머신, Docker 자체 및 Boot2Docker 관리 유틸리티로 구성됩니다. MacOS 및 Windows용 공식 설치 지침에 따라 이러한 플랫폼에 Docker를 설치할 수 있습니다.
도커 사용
간단한 예를 들어 이 섹션을 시작하겠습니다.
docker run phusion/baseimage echo "Hello Moby Dock. Hello Molly."
다음 출력이 표시되어야 합니다.
Hello Moby Dock. Hello Molly.
그러나 여러분이 생각하는 것보다 훨씬 더 많은 일이 뒤에서 일어났습니다.
- Docker Hub에서 'phusion/baseimage' 이미지를 다운로드했습니다(로컬 캐시에 아직 없는 경우).
- 이 이미지를 기반으로 하는 컨테이너가 시작되었습니다.
- 명령 echo 가 컨테이너 내에서 실행되었습니다.
- 명령이 종료될 때 컨테이너가 중지되었습니다.
처음 실행하면 텍스트가 화면에 인쇄되기 전에 지연이 나타날 수 있습니다. 이미지가 로컬로 캐시되었다면 모든 것이 1분의 1초도 걸리지 않았을 것입니다. 마지막 컨테이너에 대한 세부 정보는 docker ps -l
을 실행하여 검색할 수 있습니다.
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES af14bec37930 phusion/baseimage:latest "echo 'Hello Moby Do 2 minutes ago Exited (0) 3 seconds ago stoic_bardeen
다음 다이빙
알 수 있듯이 Docker 내에서 간단한 명령을 실행하는 것은 표준 터미널에서 직접 실행하는 것만큼 쉽습니다. 보다 실용적인 사용 사례를 설명하기 위해 이 기사의 나머지 부분에서 Docker를 활용하여 간단한 웹 서버 애플리케이션을 배포하는 방법을 살펴보겠습니다. 일을 단순하게 유지하기 위해 '/ping'에 대한 HTTP GET 요청을 처리하고 'pong\n' 문자열로 응답하는 Java 프로그램을 작성합니다.
import java.io.IOException; import java.io.OutputStream; import java.net.InetSocketAddress; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; public class PingPong { public static void main(String[] args) throws Exception { HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0); server.createContext("/ping", new MyHandler()); server.setExecutor(null); server.start(); } static class MyHandler implements HttpHandler { @Override public void handle(HttpExchange t) throws IOException { String response = "pong\n"; t.sendResponseHeaders(200, response.length()); OutputStream os = t.getResponseBody(); os.write(response.getBytes()); os.close(); } } }
도커파일
직접 Docker 이미지를 빌드하기 전에 먼저 Docker Hub 또는 액세스할 수 있는 비공개 레지스트리에 기존 이미지가 있는지 확인하는 것이 좋습니다. 예를 들어, Java를 직접 설치하는 대신 공식 이미지인 java:8
을 사용합니다.
이미지를 빌드하려면 먼저 사용할 기본 이미지를 결정해야 합니다. FROM 명령어로 표시됩니다. Docker Hub에서 제공하는 Java 8의 공식 이미지입니다. COPY 명령을 실행하여 Java 파일에 복사할 것입니다. 다음으로 RUN 으로 컴파일합니다. EXPOSE 명령은 이미지가 특정 포트에서 서비스를 제공할 것임을 나타냅니다. ENTRYPOINT 는 이 이미지를 기반으로 하는 컨테이너가 시작될 때 실행하려는 명령이고 CMD 는 전달할 기본 매개변수를 나타냅니다.

FROM java:8 COPY PingPong.java / RUN javac PingPong.java EXPOSE 8080 ENTRYPOINT ["java"] CMD ["PingPong"]
이 지침을 "Dockerfile"이라는 파일에 저장한 후 다음을 실행하여 해당 Docker 이미지를 빌드할 수 있습니다.
docker build -t toptal/pingpong .
Docker에 대한 공식 문서에는 Dockerfile 작성과 관련된 모범 사례 전용 섹션이 있습니다.
컨테이너 실행
이미지가 빌드되면 컨테이너로 이미지를 가져올 수 있습니다. 컨테이너를 실행할 수 있는 방법에는 여러 가지가 있지만 간단한 방법부터 시작하겠습니다.
docker run -d -p 8080:8080 toptal/pingpong
여기서 -p [port-on-the-host]:[port-in-the-container] 는 각각 호스트와 컨테이너의 포트 매핑을 나타냅니다. 또한 -d 를 지정하여 백그라운드에서 컨테이너를 데몬 프로세스로 실행하도록 Docker에 지시합니다. 'http://localhost:8080/ping'에 접속하여 웹 서버 애플리케이션이 실행 중인지 테스트할 수 있습니다. Boot2docker가 사용되는 플랫폼에서는 'localhost'를 Docker가 실행 중인 가상 머신의 IP 주소로 바꿔야 합니다.
Linux:
curl http://localhost:8080/ping
Boot2Docker가 필요한 플랫폼:
curl $(boot2docker ip):8080/ping
모든 것이 잘되면 다음과 같은 응답이 표시됩니다.
pong
만세, 우리의 첫 번째 맞춤형 Docker 컨테이너가 살아 있고 헤엄치고 있습니다! 대화식 모드 -i -t 에서 컨테이너를 시작할 수도 있습니다. 우리의 경우 bash 터미널이 표시되도록 entrypoint 명령을 무시합니다. 이제 원하는 모든 명령을 실행할 수 있지만 컨테이너를 종료하면 중지됩니다.
docker run -i -t --entrypoint="bash" toptal/pingpong
컨테이너를 시작하는 데 사용할 수 있는 더 많은 옵션이 있습니다. 몇 가지만 더 살펴보겠습니다. 예를 들어 컨테이너 외부에 데이터를 유지하려면 -v 를 사용하여 호스트 파일 시스템을 컨테이너와 공유할 수 있습니다. 기본적으로 액세스 모드는 읽기-쓰기이지만 컨테이너 내 볼륨 경로에 :ro
를 추가하여 읽기 전용 모드로 변경할 수 있습니다. 볼륨은 이미지에 저장되어서는 안 되는 컨테이너 내부의 자격 증명 및 개인 키와 같은 보안 정보를 사용해야 할 때 특히 중요합니다. 또한 예를 들어 로컬 Maven 저장소를 컨테이너에 매핑하여 인터넷을 두 번 다운로드하지 않도록 하여 데이터 중복을 방지할 수도 있습니다.
Docker에는 컨테이너를 함께 연결할 수 있는 기능도 있습니다. 연결된 컨테이너는 노출된 포트가 없더라도 서로 통신할 수 있습니다. –link other-container-name 으로 달성할 수 있습니다. 다음은 위에서 언급한 매개변수를 결합한 예입니다.
docker run -p 9999:8080 --link otherContainerA --link otherContainerB -v /Users/$USER/.m2/repository:/home/user/.m2/repository toptal/pingpong
기타 컨테이너 및 이미지 작업
당연히 컨테이너와 이미지에 적용할 수 있는 작업 목록은 다소 깁니다. 간결함을 위해 그 중 몇 가지만 살펴보겠습니다.
- stop - 실행 중인 컨테이너를 중지합니다.
- start - 중지된 컨테이너를 시작합니다.
- commit - 컨테이너의 변경 사항에서 새 이미지를 만듭니다.
- rm - 하나 이상의 컨테이너를 제거합니다.
- rmi - 하나 이상의 이미지를 제거합니다.
- ps - 컨테이너를 나열합니다.
- 이미지 - 이미지를 나열합니다.
- exec - 실행 중인 컨테이너에서 명령을 실행합니다.
마지막 명령은 실행 중인 컨테이너의 터미널에 연결할 수 있으므로 디버깅 목적으로 특히 유용할 수 있습니다.
docker exec -i -t <container-id> bash
마이크로서비스 세계를 위한 Docker Compose
상호 연결된 컨테이너가 몇 개 이상 있는 경우 docker-compose와 같은 도구를 사용하는 것이 좋습니다. 구성 파일에서 컨테이너를 시작하는 방법과 컨테이너를 서로 연결하는 방법을 설명합니다. 관련된 컨테이너의 양과 종속성에 관계없이 docker-compose up
이라는 하나의 명령으로 모든 컨테이너를 실행하고 실행할 수 있습니다.
야생의 도커
프로젝트 수명 주기의 3단계를 살펴보고 우리의 친절한 고래가 어떻게 도움이 될 수 있는지 살펴보겠습니다.
개발
Docker는 로컬 개발 환경을 깨끗하게 유지하는 데 도움이 됩니다. Java, Kafka, Spark, Cassandra 등과 같은 서로 다른 서비스의 여러 버전을 설치하는 대신 필요할 때 필요한 컨테이너를 시작 및 중지할 수 있습니다. 한 단계 더 나아가 종속성 버전의 혼합을 피하면서 여러 소프트웨어 스택을 나란히 실행할 수 있습니다.
Docker를 사용하면 시간, 노력 및 비용을 절약할 수 있습니다. 프로젝트가 설정하기 매우 복잡한 경우 "도커화"하십시오. Docker 이미지를 한 번 생성하는 수고를 겪으면 이 시점부터 모든 사람이 순식간에 컨테이너를 시작할 수 있습니다.
또한 로컬(또는 CI)에서 "통합 환경"을 실행하고 스텁을 Docker 컨테이너에서 실행되는 실제 서비스로 교체할 수도 있습니다.
테스트 / 지속적인 통합
Dockerfile을 사용하면 재현 가능한 빌드를 쉽게 달성할 수 있습니다. 모든 빌드에 대해 Docker 이미지를 생성하도록 Jenkins 또는 기타 CI 솔루션을 구성할 수 있습니다. 나중에 참조할 수 있도록 일부 또는 모든 이미지를 비공개 Docker 레지스트리에 저장할 수 있습니다.
Docker를 사용하면 테스트해야 할 항목만 테스트하고 방정식에서 환경을 제거합니다. 실행 중인 컨테이너에서 테스트를 수행하면 상황을 훨씬 더 예측 가능하게 유지할 수 있습니다.
소프트웨어 컨테이너가 있는 또 다른 흥미로운 기능은 동일한 개발 설정으로 슬레이브 머신을 쉽게 스핀아웃할 수 있다는 것입니다. 클러스터된 배포의 부하 테스트에 특히 유용할 수 있습니다.
생산
Docker는 개발자와 운영 담당자 간의 공통 인터페이스가 되어 마찰의 원인을 제거할 수 있습니다. 또한 파이프라인의 모든 단계에서 동일한 이미지/바이너리를 사용하도록 권장합니다. 또한 환경 차이 없이 완전히 테스트된 컨테이너를 배포할 수 있으므로 빌드 프로세스에서 오류가 발생하지 않도록 합니다.
애플리케이션을 프로덕션으로 원활하게 마이그레이션할 수 있습니다. 한때 지루하고 엉뚱한 과정이었던 것이 이제는 다음과 같이 간단할 수 있습니다.
docker stop container-id; docker run new-image
새 버전을 배포할 때 문제가 발생하면 언제든지 빠르게 롤백하거나 다른 컨테이너로 변경할 수 있습니다.
docker stop container-id; docker start other-container-id
... 뒤죽박죽을 남기지 않거나 일관성이 없는 상태로 물건을 두지 않도록 보장합니다.
요약
Docker가 하는 일에 대한 좋은 요약은 자체 모토인 Build, Ship, Run에 포함되어 있습니다.
- 빌드 - Docker를 사용하면 개발 환경과 프로덕션 환경 간의 불일치에 대해 걱정하지 않고 플랫폼이나 언어에 종속되지 않고 마이크로 서비스에서 애플리케이션을 구성할 수 있습니다.
- Ship - Docker를 사용하면 애플리케이션 개발, 테스트 및 배포의 전체 주기를 설계하고 일관된 사용자 인터페이스로 관리할 수 있습니다.
- 실행 - Docker는 다양한 플랫폼에서 확장 가능한 서비스를 안전하고 안정적으로 배포할 수 있는 기능을 제공합니다.
고래와 함께 즐거운 수영을 즐겨보세요!
이 작업의 일부는 Adrian Mouat의 Using Docker라는 훌륭한 책에서 영감을 받았습니다.