Google Cloud Study Jam - Kubernetes 입문반 (Docker 소개)

ju_bro·2022년 7월 26일
3

Cloud Study

목록 보기
1/3
post-thumbnail

🌠 Docker 란?

  • Docker는 애플리케이션을 개발, 출시, 실행하는 데 사용하는 개방형 플랫폼입니다. Docker를 사용하면 인프라에서 애플리케이션을 분리하고 인프라를 관리형 애플리케이션처럼 처리할 수 있습니다. Docker는 코드를 더욱 빠르게 출시, 테스트, 배포하고 코드 작성과 실행 주기를 단축하는 데 도움이 됩니다.


🌠 Google Cloud Shell

  • Google Cloud Shell은 다양한 개발 도구가 탑재된 가상 머신으로, 5GB의 영구 홈 디렉토리를 제공하며 Google Cloud에서 실행됩니다. Google Cloud Shell을 사용하면 명령줄을 통해 GCP 리소스에 액세스할 수 있습니다.

  • GCP Console의 오른쪽 상단 툴바에서 Cloud Shell 열기 버튼을 클릭합니다.

  • 다음 명령어를 통해 사용중인 계정 이름 목록프로젝트 ID 목록을 표시할 수 있습니다.
    (gcloud는 Google Cloud Platform의 명령줄 도구입니다. Cloud Shell에 사전 설치되어 있으며 탭 자동 완성을 지원합니다.)
gcloud auth list
gcloud config list project

✔ 명령어 출력 결과



🌠 Hello World

  • Cloud Shell을 열고 다음 명령어를 실행하여 hello world 컨테이너를 실행합니다.
docker run hello-world
  • 이 간단한 컨테이너는 화면에 Hello from Docker! 를 반환합니다.

✔ 명령어 출력 결과

코드 실행 과정을 살펴보면 다음과 같습니다.

 1. Docker 데몬이 hello-world 이미지를 검색했으나 로컬에서 이미지를 찾지 못했다.

 2. Docker Hub라는 공개 레지스트리에서 이미지를 가져온다.

 3. 가져온 이미지에서 컨테이너를 생성한다.

 4. 컨테이너를 실행한다.


  • 다음 명령어를 실행하여 Docker Hub에서 가져온 컨테이너 이미지를 확인합니다.
docker images

✔ 명령어 출력 결과

이미지를 Docker Hub 공개 레지스트리에서 가져왔습니다.
이미지 ID는 SHA256 해시 형식입니다.
이 필드에서는 프로비저닝된 Docker 이미지를 지정합니다.

※ SHA-256 : 현재 블록체인에서 가장 많이 채택하여 사용되고 있는 암호 방식이다. 단방향성의 성질을 띄고 있는 암호화 방법으로 복호화가 불가능하며 출력 속도가 빠르다는 장점을 갖고 있다.

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

📌 핵심 : Docker 데몬이 로컬에서 이미지를 찾을 수 없으면 기본적으로 공개 레지스트리에서 이미지를 검색합니다.


  • 다음 명령어를 실행하여 다시 한 번 컨테이너를 실행합니다.
docker run hello-world

✔ 명령어 출력 결과

두 번째 실행했을 때는 Docker 데몬이 로컬 레지스트리에서 이미지를 찾고 해당 이미지에서 컨테이너를 실행하였음을 확인할 수 있습니다.

※ 레지스트리 : 윈도우계열 시스템에서 사용하는 시스템 구성 정보를 저장한 데이터베이스를 말한다.

📌 핵심 : Docker 데몬이 반드시 Docker Hub에서 이미지를 가져올 필요는 없습니다.


  • 다음 명령어를 통해 실행 중인 컨테이너를 확인합니다.
docker ps

✔ 명령어 출력 결과

실행 중인 컨테이너가 없습니다.
앞서 실행한 hello-world 컨테이너는 이미 종료되었습니다.

  • 실행이 완료된 컨테이너를 포함하여 모든 컨테이너를 보기 위해 다음 명령어를 실행 합니다.
docker ps -a

✔ 명령어 출력 결과

실행이 완료된 컨테이너의 UUID와 실행에 관한 추가 메타데이터를 확인할 수 있습니다.
이때, 컨테이너 Names는 무작위로 생성되지만 docker run --name [container-name] hello-world를 사용하여 지정할 수도 있습니다.



🌠 빌드

  • 다음 명령어를 통해 test라는 이름의 폴더를 만들고 해당 폴더로 전환합니다.
mkdir test && cd test
  • 전환된 폴더에서 Dockerfile을 만들어 줍니다.
cat > Dockerfile <<EOF
# 공식 노드 런타임을 상위 이미지로 사용합니다.
FROM node:6
# 컨테이너의 작업 디렉토리를 /app으로 설정합니다.
WORKDIR /app
# 현재 디렉토리 내용을 /app에 있는 컨테이너에 복사합니다.
ADD . /app
# 컨테이너의 포트 80을 외부에 공개합니다.
EXPOSE 80
# 컨테이너가 시작될 때 노드를 사용하여 app.js를 실행합니다.
CMD ["node", "app.js"]
EOF

✔ 명령어 입력

첫 번째 행은 기본 상위 이미지를 지정합니다. 이 경우에는 노드 버전 6의 공식 Docker 이미지입니다.
두 번째 행은 컨테이너의 (현재) 작업 디렉토리를 설정합니다.
세 번째 행은 현재 디렉토리의 내용("."으로 표시)을 컨테이너에 추가합니다.
그런 다음 컨테이너의 포트를 공개하여 공개된 컨테이너 포트에서의 연결을 허용하고 마지막으로 노드 명령어를 실행하여 애플리케이션을 시작합니다.


  • 이미지 빌드를 위해 다음 명령을 실행시켜 노드 애플리케이션을 생성합니다.
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 서버로 포트 80을 수신하고 'Hello World'를 반환합니다.


  • 다음 명령어를 통해 이미지를 빌드합니다.

(이때, Dockerfile이 있는 디렉토리에서 실행해야 하기 때문에 현재 디렉토리를 의미하는 ' . '을 사용합니다.)

docker build -t node-app:0.1 .

✔ 명령어 출력 결과

-t는 name:tag 구문을 사용하여 이미지의 이름과 태그를 지정하는 역할을 합니다.
(이미지 이름 : "node-app", 태그 : "0.1")
태그를 지정하지 않으면 태그가 기본값인 latest로 지정되어 최신 이미지와 기존 이미지를 구분하기 어려워집니다.
따라서, Docker 이미지를 빌드할 때는 태그를 사용하는 것이 좋습니다.


  • 다음 명령어를 통해 빌드한 이미지를 확인합니다.
docker images

✔ 명령어 출력 결과

node는 기본 이미지이고 node-app은 사용자가 빌드한 이미지입니다.
정상적으로 이름과 태그가 지정된 것을 확인할 수 있습니다.



🌠 실행

  • 다음 명령어를 통해 빌드한 이미지를 기반으로 하는 컨테이너를 실행합니다.
docker run -p 4000:80 --name my-app node-app:0.1

✔ 명령어 출력 결과

-p는 Docker가 컨테이너의 포트 80에 호스트의 포트 4000을 매핑하도록 지시하는 플래그입니다.
--name 플래그를 사용하면 컨테이너 이름을 지정할 수 있습니다.
이제 http://localhost:4000에서 서버에 접속할 수 있습니다.
(만약 포트 매핑이 없으면 localhost에서 컨테이너에 접속할 수 없습니다.)


  • 다른 터미널을 열고 서버를 테스트합니다.
curl http://localhost:4000

✔ 명령어 출력 결과

이 경우에는 초기 터미널이 실행되는 동안 컨테이너가 실행되는 모습을 볼 수 있습니다.


  • 컨테이너를 터미널 세션에 종속시키지 않고 백그라운드에서 실행시키기위해 -d 플래그를 지정합니다.
docker run -p 4000:80 --name my-app -d node-app:0.1
docker ps

✔ 명령어 출력 결과

docker ps의 결과를 통해 컨테이너가 실행 중임을 확인할 수 있습니다.


  • docker logs [container_id]를 실행하여 로그를 확인합니다.
    (만약 컨테이너가 실행 중이라면 -f 옵션을 추가로 사용합니다.)
docker logs [container_id]

✔ 명령어 출력 결과

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


  • 아래의 과정을 통해 app.js 애플리케이션을 수정하여 새 이미지를 빌드하고 0.2로 태그를 지정합니다.

1) 텍스트 편집기(nano 또는 vim)로 app.js의 'Hello World'를 'Welcome to Cloud'로 수정합니다.

....
const server = http.createServer((req, res) => {
    res.statusCode = 200;
      res.setHeader('Content-Type', 'text/plain');
        res.end('Welcome to Cloud\n'); # 수정 부분
});
....

2) 새 이미지를 빌드하고 0.2로 태그를 지정한 후 다른 컨테이너를 실행합니다.
이때, 호스트 포트를 80 대신 8080으로 매핑합니다.
(호스트 포트 4000은 이미 사용 중이므로 사용할 수 없음)

docker build -t node-app:0.2 .
docker run -p 8080:80 --name my-app-2 -d node-app:0.2
docker ps
curl http://localhost:8080

✔ 명령어 출력 결과

실행 중인 컨테이너를 확인한 결과 app.js 애플리케이션이 tag 0.1에 port 번호 4000과 tag 0.2에 port 번호 8080으로 각각 실행 중인 것을 볼 수 있습니다.



🌠 디버깅

📌 실습환경 변경으로 인하여 [container_id]가 기존 '47bffefaf6ab'에서 'd3a4ddbc3a67'로 변경됨을 유의하여 주세요.

  • docker exec를 사용하여 실행 중인 컨테이너에서 대화식 Bash 세션을 시작합니다.
docker exec -it [container_id] bash

✔ 명령어 출력 결과

-it 플래그는 pseudo-tty를 할당하고 stdin을 열린 상태로 유지하여 컨테이너와 상호작용할 수 있도록 합니다.
Dockerfile에 지정된 WORKDIR 디렉토리(/app)에서 bash가 실행된 것을 확인할 수 있습니다.
이제 디버깅할 컨테이너 내에서 대화형 셸 세션을 사용할 수 있습니다.


  • 대화식 Bash 세션에서 다음 명령어를 통해 디렉토리를 확인하고 종료합니다.
ls
exit

✔ 명령어 출력 결과


  • Docker inspect를 통해 Docker에서 컨테이너의 메타데이터를 전부 검토할 수 있습니다.
    이때, --format을 사용하여 반환된 JSON의 특정 필드를 검사합니다.
docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' [container_id]

✔ 명령어 출력 결과



🌠 게시

  • Docker 컨테이너의 이식성을 시연하기 위해 다음과 같은 과정을 거칩니다.
  1. 이미지를 Google Container Registry(GCR)로 푸시합니다.
  2. 모든 컨테이너와 이미지를 제거하여 새로운 환경을 시뮬레이션합니다.
  3. 컨테이너를 가져와서 실행합니다.
  • GCR에서 호스팅하는 비공개 레지스트리에 이미지를 푸시하려면 이미지에 레지스트리 이름으로 태그를 지정해야 합니다.

📌 이때, 양식은 [hostname]/[project-id]/[image]:[tag]입니다.

  • GCR의 경우
    [hostname]= gcr.io
    [project-id]= 프로젝트의 ID
    [image]= 이미지 이름
    [tag]= 원하는 임의의 문자열 태그입니다. (지정하지 않으면 기본값인 'latest'로 설정)

1) 이미지를 Google Container Registry(GCR)로 푸시합니다.

  • 다음 명령어를 통해 프로젝트 ID를 찾습니다.
gcloud config list project

✔ 명령어 출력 결과


  • 다음 명령어를 통해 node-app:0.2를 태그하고 [project-id]를 내 구성으로 바꾼 후 컨테이너 이미지를 확인합니다.
docker tag node-app:0.2 gcr.io/[project-id]/node-app:0.2
docker images

✔ 명령어 출력 결과


  • 해당 이미지를 GCR로 푸시합니다.
docker push gcr.io/[project-id]/node-app:0.2

✔ 명령어 출력 결과


✔ 확인 결과


2) 모든 컨테이너와 이미지를 제거하여 새로운 환경을 시뮬레이션합니다.

  • 다음 명령어를 통해 모든 컨테이너를 중지하고 제거합니다.
  • 추가로 노드 이미지를 제거하기 전에 (node:6의) 하위 이미지를 제거해야 합니다.
docker stop $(docker ps -q)
docker rm $(docker ps -aq)
#추가
docker rmi node-app:0.2 gcr.io/[project-id]/node-app node-app:0.1
docker rmi node:6
docker rmi $(docker images -aq) # 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

✔ 명령어 출력 결과

tag가 0.2인 이미지를 푸시하여 port번호 4000으로 컨테이너를 실행한 후 localhost:4000을 확인해보니 기존의 'Hello World'가 아닌 'Welcome to Cloud'가 출력되는 것을 확인할 수 있습니다.



🌠 정리

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

🎉 평가 완료 인증 🎉



이 글은 "Google Cloud Study Jam"의 [Kubernetes 입문반] 강좌 실습 후 개인적으로 학습하기 위해 정리한 글입니다. 🙂

https://www.cloudskillsboost.google/quests/29

profile
Inha University

3개의 댓글

comment-user-thumbnail
2022년 7월 29일

클라우드 맛집이네요 :D
잘 먹고 갑니다 ^^

1개의 답글