Today I Learned

[쿠버네티스 인 액션] 2. 도커와 쿠버네티스 첫걸음 (1) 본문

쿠버네티스

[쿠버네티스 인 액션] 2. 도커와 쿠버네티스 첫걸음 (1)

하이라이터 2022. 7. 15. 02:40
728x90

2장에서 다루는 내용

  • 도커를 사용한 컨테이너 이미지 생성, 실행, 공유
  • 로컬에서 단일 노드 쿠버네티스 클러스터 실행
  • 구글 쿠버네티스 엔진에서 쿠버네티스 클러스터 설치
  • kubectl CLI 클라이언트 설정과 사용
  • 쿠버네티스에서 애플리케이션의 배포와 수평 스케일링

2.1 도커를 사용한 컨테이너 이미지 생성, 실행, 공유하기

먼저 도커 사용의 기본적인 방법을 소개한다.

  1. 도커 설치와 "Hello world" 컨테이너 실행하기
  2. 쿠버네티스에 배포할 간단한 Node.js 애플리케이션 실행하기
  3. 격리된 컨테이너로 실행하기 위해 애플리케이션을 컨테이너 이미지로 패키징하기
  4. 이미지 기반의 컨테이너 실행하기
  5. 누그든 실행할 수 있게 도커 허브(Docker Hub)에 이미지 푸시하기

2.1.1 도커 설치와 Hello World 컨테이너 실행하기

  • 리눅스 머신에 도커를 설치하거나, 맥이나 윈도우 환경에서는 가상머신 안에 도커 데몬이 구동된다.
  • https://docs.docker.com/engine/install/ 의 설명에 따라 운영체제에 알맞은 방식으로 설치한다.
  • 도커 공개 레지스트리인 도커 허브에 있는 busybox 이미지를 pull하여 echo "hello world" 명령을 실행할 수 있다.

Hello World 컨테이너 실행

  • busybox는 echo, ls, gzip 등과 같은 표준 UNIX 명령줄 도구들을 합쳐 놓은 단일 실행파일이다.
  • docker run 커맨드를 사용해 어떤 이미지를 다운로드하고 실행할지, 필요하다면 실행할 다른 명령어를 추가적으로 기술하면 된다.

백그라운드에 일어난 동작 이해하기

  • 먼저 도커는 busybox:lastest 이미지가 로컬 컴퓨터에 존재하는지 체크한다.
  • 존재하지 않느다면 docker.io의 도커 허브 레지스트리에서 이미지를 다운로드한다.
  • 이미지 다운로드가 완료되면 도커는 이미지로부터 컨테이너를 생성하고 컨테이너 내부에서 명령어를 실행한다.

다른 이미지 실행하기

$docker run <image>

컨테이너 이미지에 버전 지정하기

  • 도커는 동일한 이미지와 이름에 여러 개의 버전을 가질 수 있다. 이미지를 참조할 때 명시적으로 태그를 지정하지 않으면, lastest 태그를 참조한 것으로 간주한다.
$docker run <image>:<tag>

2.1.2 간단한 node.js 애플리케이션 실행하기

  • 간단한 node.js 웹 애플리케이션을 만들고 컨테이너 이미지로 패키징한다.
  • 애플리케이션은 HTTP 요청을 받아 애플리케이션이 실행 중인 머신의 호스트 이름을 응답으로 반환한다.
  • 이렇게하면 호스트 머신의 호스트 이름이 아닌 애플리케이션이 실행 중인 컨테이너 내부의 호스트 이름을 바라보는 것을 알 수 있다.
/* 단일 node.js 애플리케이션 : app.js */
const http = require('http');
const os = require('os');

console.log("Kubia server starting...");

var handler = function(request, response) {
  console.log("Received request from " + request.connection.remoteAddress);
  response.writeHead(200);
  response.end("You've hit " + os.hostname() + "\n");
};

var www = http.createServer(handler);
www.listen(8080);
  • 이제 node.js를 다운로드하고 설치해 직접 테스트해볼 수 있지만 그렇게 할 필요가 없다. 도커를 통해 애플리케이션을 컨테이너 이미지로 패키징하면 다운로드를 하거나 설치하지 않고도 어디서든 실행할 수 있기 때문이다.

2.1.3 이미지를 위한 Dockerfile 생성

  • 애플리케이션을 이미지로 패키징하기 위해 먼저 DockerFile이라고 부르는 파일을 생성해야 한다.
  • Dockerfiler에는 도커가 이미지를 생성하기 위해 수행해야 할 지시 사항이 담겨져 있다.
  • app.js 파일과 동일한 디렉터리에 있어야 한다.
/* 애플리케이션 컨테이너를 이미지로 만들기 위한 Dockfile */
FROM node:7
ADD app.js /app.js
ENTRYPOINT ["node", "app.js"]
  • FROM 줄은 시작점(이미지 생성의 기반이 되는 기본 이미지)으로 사용할 컨테이너 이미지를 정의한다.
  • 두 번째 줄은 로컬 디렉터리의 app.js 파일을 이미지 루트의 디렉터리에 동일한 이름으로 추가한다.
  • 세 번째 줄에서는 이미지를 실행했을 때 수행되어야 할 명령어를 정의한다. 이 경우는 node app.js 이다.


2.1.4 컨테이너 이미지 생성

  • Dockerfile과 app.js 파일을 생성헀으므로 이미지를 빌드하기 위한 준비는 끝났다.
  • 이미지를 빌드하기 위해 다음 도커 명령어를 실행한다.
$docker build -t kubia .
  • 도커에게 현재 디렉터리의 컨텐트를 기반으로 kubis라고 부르는 이미지를 빌드하라고 요청했다.
  • 도커는 디렉터리 내 Dockerfiler을 살펴보고 파일에 명시된 지시 사항에 근거해 이미지를 빌드한다.

어떻게 이미지가 빌드되는지 이해하기

  • 빌드 프로세스는 도커 클라이언트가 수행하지 않는다. 디렉터리의 전체 콘텐츠가 도커 데몬에 업로드되고 그곳에서 이미지가 빌드된다.
  • 도커 클라이언트와 데몬이 같은 머신에 있을 필요는 없다. 리눅스가 아닌 경우 도커 클라이언트는 호스트 OS에 위치하고, 데몬은 가상머신 내부에서 실행된다.
  • 빌드 프로세스 동안 이미지가 사용자 컴퓨터에 저장되어 있지 않다면, 도커는 기본 이미지(node:7)를 퍼블릭 이미지 리포지터리에서 가져온다.

이미지 레이어에 관해 이해하기

  • 이미지는 하나의 큰 바이너리 덩어리가 아니라 여러 개의 레이어로 구성된다.
  • 각 DockerFiler은 새로운 레이어를 하나만 생성하는 것이 아니다.
  • 이미지를 빌드하는 동안 기본 이미지의 모든 레이어를 가져온 다음, 도커는 그 위에 새로운 레이어를 생성하고 app.js 파일을 그 위에 추가한다.
  • 그런 다음 이미지가 실행될 때 수행되어야 할 명령을 지정하는 또 하나의 레이어를 추가한다. 이 마지막 레이어는 kubia:lastest 라고 태그를 지정한다.

  • 이미지 빌드 프로세스가 완료되면 새로운 이미지가 로컬에 저장된다.
  • 로컬에 저장된 이미지 리스트를 도커에게 요청할 수 있다.

Dockerfile을 이용한 이미지 빌드와 수동 빌드 비교하기

  • Dockerfile은 도커로 컨테이너 이미지를 생성하는 일반적인 방법이지만, 기존 이미지에서 컨테이너를 실행하고 컨테이너 내부에서 명령어를 수행한 후 빠져나와 최종 상태를 새로운 이미지를 commit하는 방법으로 이미지를 수동으로 생성할 수도 있다.
  • 이는 Dockerfile로부터 빌드하는 것과 정확히 동일하지만 Dockerfile을 이용하는 것이 훨씬 반복 가능하고 이미지 빌드를 자동화할 수 있는 방법이다.

2.1.5 컨테이너 이미지 실행

$docker run --name kubia-container -p 8080:8080 -d kubia
  • 이 명령어는 도커가 kubia 이미지에서 kubia-container라는 이름의 새로운 컨테이너를 실행하도록 한다.
  • 컨테이너는 콘솔에서 분리돼(-d 플래그) 백그라운드에서 실행됨을 의미한다.
  • 로컬 머신의 8080 포트가 컨테이너 내부의 8080 포트와 매핑되므로 (-p 8080:8080) http://localhost:8080으로 애플리케이션에 접근할 수 있다.
  • 로컬 머신에서 도커 데몬이 실행중이 아니라면, localhost 대신에 데몬이 실행 중인 가상머신의 호스트 이름이나 IP를 사용해야 한다. 이 정보는 DOCKER_HOST 환경변수로 확인 가능하다.

애플리케이션 접근하기

실행중인 모든 컨테이너 조회하기

  • 실행중인 모든 컨테이너를 조회해서 리스트를 확인할 수 있으며, 도커는 각 컨테이너의 ID, 이름, 컨테이너를 실행하는데 사용된 이미지, 컨테이너 내부에 수행된 명령어를 출력한다.

컨테이너에 관한 추가 정보 얻기

  • docker ps 명령어는 컨테이너 기본 정보만을 표시하며, 자세한 정보를 보려면 docker inspect를 사용한다.
$docker inspect kuia-container

2.1.6 실행중인 컨테이너 내부 탐색하기

  • 하나의 컨테이너 내에 여러 개의 프로세스가 실행될 수 있기 떄문에 추가 프로세스를 실행해서 컨테이너 내부를 살펴볼 수 있다.

실행 중인 컨테이너 내부에서 셸 실행하기

  • 기본 이미지인 Node.js는 bash 셸을 포함하고 있으므로 다음과 같이 컨테이너 내부에서 셸을 실행할 수 있다.
$docker exec -it kubia-container bash
  • bash 프로세스는 컨테이너의 메인 프로세스와 동일한 리눅스 네임스페이스를 갖는다. 따라서 컨테이너 내부에서 실행될 때 Node.js와 애플리케이션이 시스템을 보는 방법을 알 수 있다.
  • -it 옵션
    • -i : 표준 입력(STDIN)을 오픈 상태로 유지한다. 셸에 명령어을 입력하기 위해 필요하다.
    • -t : 의사 터미널(TTY)을 할당한다.

내부에서 컨테이너 탐색

  • 다음과 같이 컨테이너 내부에 실행중인 프로세스를 조회할 수 있다.

  • 단지 세 개의 프로세스만 볼 수 있고 호스트 운영체제의 다른 프로세스는 볼 수가 없다.

호스트 운영체제에서 실행 중인 컨테이너에서 실행되는 프로세스 이해하기

  • 이제 다른 터미널을 열고 호스트 운영체제의 프로세스를 조회해보면 모든 프로세스를 조회할 수 있는데, 컨테이너에서 실행중인 프로세스도 볼 수 있다.

  • 이는 컨테이너에서 실행중인 프로세스가 호스트 운영체제에서 실행중이라는 것을 증명한다.
  • 호스트 운영체제와 컨테이너 내부에서 조회한 프로세스의 ID가 다르다는 것을 확인할 수 있는데, 컨테이너는 자체 리눅스 PID 네임스페이스를 사용하며 고유의 시퀀스 번호를 가지고 완전히 분리된 프로세스 트리를 갖고 있다.

격리된 컨테이너 파일 시스템

  • 각 컨테이너는 격리된 파일 시스템을 갖고 있다.


2.1.7 컨테이너 중지와 삭제

$docker stop kubia-container
  • 이 명령은 컨테이너에 실행중인 메인 프로세스를 중지시킨다.
  • docker ps -a 로 보면 컨테이너 그 자체는 여전히 존재함을 확인할 수 있다. -a 옵션은 실행중이거나 중지된 모든 컨테이너를 출력한다.
  • 컨테이너를 완전히 삭제하려면 rm 명령어를 수행해야 한다.
$docker rm kubia-container

2.1.8 이미지 레지스트리에 이미지 푸시

  • 빌드한 이미지는 로컬에서만 사용 가능하며 다른 컴퓨터에서 실행하려면 외부 이미지 저장소에 이미지를 푸시해야 한다.
  • 사설 이미지 레지스트리를 설정하거나 공개 레지스트리를 사용할 수 있다.
  • 공개 레지스트리인 도커 허브(http://hub.docker.com)을 사용하려면 이미지 태그를 다시 지정해야 한다.
  • 도커 허브는 리포지터리 이름이 도커 허브 ID로 시작해야만 이미지를 푸시할 수 있다.

추가 태그로 이미지 태그 지정

$docker tag kubia highlighter9/kubia
  • 이 명령은 태그를 변경하지 않으며, 같은 이미지에 추가적인 태그를 생성한다.

도커 허브에 이미지 푸시하기

  • 도커 허브에 이미지를 푸시하기 전에 docker login 명령을 이용해 사용자 ID로 로그인해야 한다.
$docker push highlighter9/kubia

다른 머신에서 이미지 실행하기

  • 이제 다음 명령어를 통해 도커를 실행하는 모든 머신에 이미지를 실행할 수 있다.
$docker run -p 8080:8080 -d highlighter9/kubia
728x90
Comments