[Kubernetes in Google Cloud] Lab1) Introduction to Docker

Speedwell🍀·2022년 7월 18일
0
post-thumbnail

실습 링크

Overview

In this lab

  • create, run, and debug containers
  • pull and push images to and from Google Container Registry

➡ basic Docker container environment commands에 익숙해지기!


Docker

  • open platform for developing, shipping(출시), and running applications

  • Docker를 사용했을 때의 장점

    • 인프라에서 어플리케이션을 분리하고 인프라를 관리형(managed) 어플리케이션처럼 처리 가능
    • 코드를 빠르게 출시/테스트/배포 가능
    • 코드 작성과 코드 실행 cycle(주기)을 단축 가능
      ➡ 이는 Docker가 kernel containerization 기능을 어플리케이션 관리 및 배포를 지원하는 workflows 및 도구와 결합하기 때문에 가능
  • 도커 컨테이너는 Kubernetes에서 사용할 수 있으므로 Kubernetes Engine에서 쉽게 실행될 수 있다.

  • 도커의 essentails을 배우면 Kubernetes 및 컨테이너 어플리케이션 개발을 시작하는 데 필요한 skillset을 갖출 수 있다.


What you'll learn

  • Docekr 컨테이너 빌드, 실행, 디버그

  • Docker Hub 및 Google Container Registry에서 Docker 이미지 가져오기(pull)

  • Docker 이미지를 Google Container Registry로 push


Advanced labs



실습 시작 전에 개요에서 설정 및 요구사항까지 완료된 상태여야 한다!


Hello World

  1. Cloud Shell를 열고 아래의 명령어를 입력하여 hello world 컨테이너를 실행한다.
    $ docker run hello-world
    ➡ 이 컨테이너는 "Hello from Docker!"를 리턴한다.

    • 출력된 결과에서 실행한 단계 개수에 주목해보자!

      1. docker daemon이 hello-world 이미지를 검색했으나 로컬에서 이미지를 찾지 못함

      Docker daemon

      1. listens for Docker API requests
      2. manages Docker objects such as images, containers, networks, and volumes
      3. communicates with other daemons to manage Docker services
      1. Docker Hub이라는 공개 registry에서 이미지를 pull
      2. 가져온 이미지에서 컨테이너를 생성
      3. 컨테이너 실행

  1. 아래의 명령을 실행하여 Docker Hub에서 가져온 컨테이너 이미지를 확인해보자.
    $ docker images

    • 이미지를 Docker Hub 공개 registry에서 pull해왔다.

    • 이미지 ID는 SHA256 hash format

      • 이 필드에서는 provisioned된 docker 이미지를 지정한다.

        프로비저닝(provisioning): 사용자의 요구에 맞게 시스템 자원을 할당, 배치, 배포해뒀다가 필요 시 시스템을 즉시 사용할 수 있는 상태로 미리 준비해 두는 것

    • docker daemon이 로컬에서 이미지를 찾을 수 없으면 default로 공개 registry에서 이미지를 검색한다.


  1. 컨테이너를 다시 실행해보자!
    $ docker run hello-world
    • 두 번째로 실행했을 때, docker daemon이 local registry에서 이미지를 찾은 뒤 이미지에서 컨테이너를 실행한다.
      ➡ docker daemon이 반드시 Docker Hub에서 이미지를 가져올 필요는 없다.

  1. 아래의 명령어를 통해 실행 중인 컨테이너를 확인해보자!
    $ docker ps
    • 실행중인 컨테이너가 없다.

      • 앞서 실행한 hello-world 컨테이너는 이미 종료되었기 때문

  1. 실행이 완료된 컨테이너를 포함하여 모든 컨테이너를 보려면 아래의 명령어!
    $ docker ps -a

    • docker가 컨테이너를 식별하기 위해 생성한 UUID인 CONTAINER ID와 실행에 관한 메타데이터가 표시된다.

      범용고유식별자;UUID(Universally Unique IDentifier): 기본적으로 어떤 개체(데이터)를 고유하게 식별하는 데 사용되는 16바이트(128비트) 길이의 숫자. 32개의 16진수로 구성되며, 5개의 그룹으로 표시되고 각 그룹은 하이픈으로 구분. 참고

    • 컨테이너 Names도 무작위로 생성되지만 $ docker run --name [container-name] hello-world를 사용하여 지정할 수 있다.






Build

간단한 node application 기반 docker image를 빌드해보자!

  1. test 폴더 생성 후 전환
    $ mkdir test && cd test

  2. Dockerfile 생성
    ➡ docker daemon에 이미지를 빌드하는 방법을 지시

cat > Dockerfile <<EOF
# Use an official Node runtime as the parent image
FROM node:lts
# Set the working directory in the container to /app
WORKDIR /app
# Copy the current directory contents into the container at /app
ADD . /app
# Make the container's port 80 available to the outside world
EXPOSE 80
# Run app.js using node when the container launches
CMD ["node", "app.js"]
EOF
  • 첫 번째 행
    • 기본 상위 이미지 지정
    • 이 경우에는 노드 버전 lts(long term support)의 공식 이미지
  • 두 번째 행
    • 컨테이너의 (현재) 작업 디렉토리를 지정
  • 세 번째 행
    • 현재 디렉토리의 내용을 컨테이너에 추가
  • 네 번째 행
    • 컨테이너의 포트를 공개하여 공개된 컨테이너 포트에서의 연결을 허용
  • 다섯 번째 행
    • 노드 명령어를 실행하여 어플리케이션 시작

Dockerfile 명령어 참조를 자세히 읽어보고 Dockerfile의 각 행에 관해 숙지하기!


  1. 노드 어플리케이션을 작성한 다음 이미지를 빌드해보자!
    • 아래의 명령을 실행하여 노드 어플리케이션 생성
    cat > app.js <<EOF
    const http = require('http');
    const hostname = '0.0.0.0';
    const port = 80;
    const server = http.createServer((req, res) => {
        res.statusCode = 200;
        res.setHeader('Content-Type', 'text/plain');
        res.end('Hello World\n');
    });
    server.listen(port, hostname, () => {
        console.log('Server running at http://%s:%s/', hostname, port);
    });
    process.on('SIGINT', function() {
        console.log('Caught interrupt signal and will exit');
        process.exit();
    });
    EOF
    ➡ 간단한 HTTP 서버로 port 80을 수신하고 "Hello World"를 반환

  1. 이미지 빌드

    • 아래의 명령어를 Dockerfile이 있는 디렉토리에서 실행
      $ docker build -t node-app:0.1 .

      ➡ 이미지를 빌드할 때 위 Dockerfile의 각 행을 통해 중간 컨테이너 레이어가 만들어지는 방식을 확인하자!

    • -tname:tag syntax를 사용하여 이미지의 이름과 태그를 지정

      • 이미지 이름: node-app
      • 이미지 태그: 0.1

    docker 이미지를 빌드할 때는 태그를 지정하는 것이 좋다.
    태그를 지정하지 않으면 태그가 기본값인 latest로 지정되어 최신 이미지와 기본 이미지를 구분하기 어려워진다.


  1. 아래의 명령어를 통해 빌드한 이미지를 확인해보자!
    $ docker images

    • node: 기본 이미지
    • node-app: 사용자가 빌드한 이미지
      node를 제거하려면 우선 node-app을 제거해야 한다.
    • 이미지의 사이즈는 VM에 비해 상대적으로 작다.
    • node:slimnode:alpine과 같은 노드 이미지의 다른 버전을 사용하면 더 작은 이미지를 제공하여 이식성을 높일 수 있다.

      컨테이너 크기를 줄이는 주제는 Advanced Topics에서 다룬다. official repository에서 모든 버전 확인 가능.






Run

  1. 이 모듈에서는 위의 코드를 사용하여 빌드한 이미지를 기반으로 하는 컨테이너 실행
    $ docker run -p 4000:80 --name my-app node-app:0.1

    • --name flag를 사용하면 컨테이너 이름을 지정할 수 있다.
    • -p는 docker가 컨테이너의 포트 80에 호스트의 포트 4000을 매핑하도록 지시하는 flag
      ➡ 이제 http://localhost:4000에서 서버에 접속할 수 있다.
      (포트 매핑이 없으면 localhost에서 컨테이너에 접속할 수 없다.)

  1. 다른 터미널을 열고 서버 테스트
    $ curl http://localhost:4000

    • 초기 터미널이 실행되는 동안 컨테이너가 실행된다.
    • 컨테이너를 터미널 세션에 종속시키지 않고 백그라운드에서 실행하려면 -d flag를 지정해야 한다.

  1. 초기 터미널을 닫은 후 아래의 명령어를 실행하여 컨테이너를 중단/삭제
    $ docker stop my-app && docker rm my-app

  1. 아래의 명령어를 실행하여 백그라운드에서 컨테이너 시작
    $ docker run -p 4000:80 --name my-app -d node-app:0.1

    $ docker ps

    ➡ 컨테이너가 docker ps 결과에서 실행 중

  1. $ docker logs [container_id]를 실행하면 로그를 볼 수 있다.

    Tips) 초기 문자가 컨테이너를 고유하게 식별하는 한, 전체 컨테이너 ID를 작성할 필요는 없다.
    예를 들어 컨테이너 ID가 '17bcaca6f...'일 경우 'docker logs 17b'를 실행할 수 있다.


  1. 어플리케이션을 수정해보자.
    • $ cd test
    • $ nano app.js를 통해 app.js를 편집
      - 'Hello World\n'를 'Welcome to Cloud\n'로 수정

  1. 새로운 이미지를 빌드하고 0.2로 태그 지정
    $ docker build -t node-app:0.2

    • 2단계에서 기존 cache layer를 사용하고 있음에 주목하자!
      • app.js를 변경했기 때문에 3단계 이후부터 레이어가 수정

  1. 새 이미지 버전으로 다른 컨테이너 실행
    $ docker run -p 8080:80 --name my-app-2 -d node-app:0.2
    • 이때 호스트 포트를 80대신 8080으로 매핑
      - 호스트 포트 4000은 이미 사용 중이므로 사용 불가

      $ docker ps


  1. 컨테이너 테스트

    • 처음 작성한 컨테이너 테스트
      $ curl http://localhost:4000

    • 두 번째로 작성한 컨테이너 테스트
      $ curl http://localhost:8080






Debug

  1. 컨테이너 로그 확인

    $ docker logs [container_id]

    • 컨테이너가 실행 중일 때 로그 확인은 -f 옵션 필요
      $ docker logs -f [container_id]

  1. 실행 중인 컨테이너에서 대화식 Bash 세션 시작 가능

    다른 터미널을 열고 아래의 명령어 입력하기
    $ docker exec -it [container_id] bash

    • -it flag는 pseudo-tty를 할당하고 stdin을 열린 상태로 유지하여 컨테이너와 상호작용할 수 있게 함

      pseudo-tty(pseudoterminal or PTY): used by users and applications to gain access to the shell
      stdin: 표준 입력(stdin)은 프로그램으로 들어가는 데이터(보통은 문자열) 스트림

    • Dockerfile에 지정된 WORKDIR 디렉토리(/app)에서 bash가 실행된 것을 확인 가능
    • $ ls
    • 새 터미널에 $ exit 명령어를 입력하여 Bash 세션 종료

  1. Docker에서 컨테이너의 메타데이터 검토 가능
    • $ docker inspect [container_id]
    • --format을 사용하여 반환된 JSON의 특정 필드를 검사

디버깅에 관한 자세한 내용은 아래의 리소스 참조하기






Publish

이제 이미지를 Google Container Registry(GCR)로 push하자!

그 후, 모든 컨테이너와 이미지를 제거하여 새로운 환경을 시뮬레이션하고 컨테이너를 가져와서 실행해보자!
➡ 이를 통해 docker 컨테이너의 이식성(portability)을 시연(demonstrate)


GCR에서 호스팅하는 비공개 registry에 이미지를 push하려면 이미지에 registry 이름으로 태그를 지정해야 한다.

양식: [hostname]/[project-id]/[image]:[tag]

GCR의 경우 [hostname] = gcr.io


$ gcloud config list project를 실행하여 프로젝트 ID를 찾을 수 있다.


node-app:0.2를 태그해보자.
$ docker tag node-app:0.2 gcr.io/[project-id]/node-app:0.2
$ docker images


이 이미지를 GCR로 push하자!
$ docker push gcr.io/[project-id]/node-app:0.2


웹 브라우저의 이미지 레지스트리로 이동하여 GCR에 이미지가 있는지 확인해보자!

방법1) 콘솔에서 도구 > Container Regsitry
방법2) http://gcr.io/[project-id]/node-app


이미지를 테스트해보자!

여기서는 간단하게 모든 컨테이너와 이미지를 제거하여 새로운 환경을 시뮬레이션해보자!

새로운 VM을 시작하고 SSH로 새 VM에 접속한 다음 gcloud를 설치해도 된다.

SSH(Secure SHell): 원격 호스트에 접속하기 위해 사용되는 보안 프로토콜

  1. 모든 컨테이너를 중지 & 제거
    $ docker stop $(docker ps -q)
    $ docker rm $(docker ps -aq)

  2. 노드 이미지 제거 전에 (node:lts의) 하위 이미지 제거
    $ docker rmi node-app:0.2 gcr.io/[project-id]/node-app node-app:0.1
    $ docker rmi node:lts
    $ docker rmi $(docker images -ap) # remove remaining images
    $ docker images

    이제 새로운 환경과 같아졌다.

  3. 이미지를 푸시하여 실행
    $ docker pull gcr.io/[project-id]/node-app:0.2
    $ docker run -p 4000:80 -d gcr.io/[project-id]/node-app:0.2
    $ curl http://localhost:4000


여기서는 컨테이너의 이식성을 확인해봤다.

  • Docker가 호스트(사내;on-premise or VM)에 설치되어 있을 경우, 공개/비공개 레지스트리에서 이미지를 가져와서 이를 기반으로 컨테이너를 실행할 수 있다.

    • Docker를 제외하면 호스트에 설치해야 하는 어플리케이션 종속 항목은 없다.




배운 내용 정리

  • Docker Hub의 공개 이미지를 기반으로 하여 컨테이너 실행
  • 컨테이너 이미지를 빌드하고 Google Container Registry로 push
  • 실행 중인 컨테이너를 디버그하는 방법 숙지
  • Google Container Registry에서 가져온 이미지를 기반으로 하여 컨테이너 실행

0개의 댓글