쿠버네티스 인 액션 - 도커와 컨테이너의 첫걸음 (1)

hyeokjin·2022년 9월 4일
1

kubernetes

목록 보기
1/9
post-thumbnail

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

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

도커 설치와 "Hello world" 컨테이너 실행

https://docs.docker.com/desktop/install/windows-install/ 에서 운영체제에 맞는 도커를 설치할 수 있다.
설치가 완료되면 도커 클라이언트 실행파일로 다양한 도커 명령을 실행할 수 있다.
도커 허브는 잘 알려진 소프트웨어 패키지를 위한 즉시 실행 가능한 이미지를 보유하고 있다. 그 가운데 하나가 busybox 이미지이며 간단하게 echo "Hello world" 명령을 실행하는데 사용된다.

busybox 이미지를 실행하기 위해 어떤 것도 다운로드하거나 설치할 필요없다.
docker run 커맨드를 사용하여 이미지를 다운로드하고 실행한다.

$ docker run busybox echo "Hello world"

단일 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);

위 코드는 포트 8080으로 HTTP 서버를 시작하고, 서버는 모든 요청에 대해 상태코드 200 OK 와 "You've hit [hostname]" 택스트를 HTTP 응답으로 한다.
요청 핸들러는 나중에 필요한 경우를 위해 클라이언트 IP 주소를 표준 출력에 로깅한다.

도커를 통해 애플리케이션을 컨테이너 이미지로 패키징하여 어디에서든 실행할 수 있다.
패키징을 하기위해 이미지를 위한 Dockerfile 생성을 해보자.

Dockerfile


FROM node:7
ADD app.js /app.js
ENTRYPOINT ["node", "app.js"]

FROM 줄은 시작점으로 사용할 컨테이너 이미지를 정의한다.
이 경우 node 컨테이너 태그 7을 사용한다.
두번째 줄은 로컬 디렉터리의 app.js 파일을 이미지의 루트 디렉터리에 동일한 이름으로 추가한다.
마지막으로 세번째 줄에서는 이미지를 실행했을 때 수행돼야 할 명령어를 정의한다.
이 경우 node app.js 이다.

컨테이너 이미지생성

Dokerfile과 app.js 파일을 생성했으므로 이미지를 빌드하려면 다음 도커 명령을 실행한다.

$ docker build -t kubia .

빌드 프로세스가 완료되면, 새로운 이미지가 로컬에 저장된다.
images 명령을 사용하면, kubia 라는 레포지토리로 빌드 한것을 확인할수 있다.

$ docker images

컨테이너 이미지실행

다음 명령어를 사용해 이미지를 실행할 수 있다.

$ docker run --name kubia-container -p 8080:8080 -d kubia

이 명령어는 도커가 kubia 이미지에서 kubia-container라는 이름의 새로운 컨테이너를 실행하도록 한다. 컨테이너는 콘솔에서 분리돼 백그라운드 에서 실행됨을 의미한다.

로컬머신의 8080포트가 컨테이너 내부의 8080포트와 매핑되므로 애플리케이션에 접근할 수 있다.

애플리케이션 접근하기

curl 명령어를 사용해 접근해보자
이 작은 애플리케이션은 격리된 컨테이너 내부에서 실행중인것을 확인할 수 있다.

$ curl localhost:8080
You've hit 44d76963e81

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

모든 컨테이너를 조회해서 리스트를 확인하다.

$ docker ps

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

$ docker inspect kubia-container

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

실행 중인 컨테이너의 기본 이미지인 node.js는 bash 셸을 포함하고 있으므로 다음과 같은 컨테이너 내부에서 셸을 실행할 수 있다.

$ docker exec -it kubia-container bash

-it 옵션은 두 옵션을 축약한 것이다

-i : 표준 입력을 오픈상태로 유지한다. 셸에 명령어를 입력하기 위해 필요하다
-t : 의사 터미널을 할당한다.

그러므로 일반적인 셸을 사용하는 것과 동일하게 사용하고 싶다면 두 옵션이 모두 필요하다.

내부에서 컨테이너 탐색

컨테이너 내부에서 프로세스 조회하려면 다음과 같은 명령을 사용한다

root@44d76963e81"/# ps aux

호스트 운영체제에서 실행 중인 컨테이너 프로세스 확인하는 방법이다

$ ps aux |  grep app.js

컨테이너 중지와 삭제

중지

$ docker stop kubia-container

삭제

$ docker rm kubia-container

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

이미지를 푸시하기 전에 도커허브의 규칙에 따라 이미지 태그를 지정해야한다.

추가 태그로 이미지 태그 지정을 한다.

$ docker tag kubia luksa/kubia

docker images 명령으로 시스템에 저장된 이미지를 조회해 추가된 태그를 확인 할 수있다.

다음으로 도커허브에 이미지를 푸시한다.

$ docker push luksa/kubia

이미지 푸시가 완료되면 모든 사람이 이미지를 사용할 수 있다.

$ docker run -p 8080:8080 -d luksa/kubia

쿠버네티스 클러스터 설치

이제 컨테이너 이미지에 애플리케이션을 패키징하고 도커 허브를 통해 사용할 수 있게 됐다. 도커에서 직접 실행하는대신 쿠버네티스 클러스터에 배포할 수 있다.
하지만 먼저 쿠버네티스 클러스터를 설치해야한다.

구글 쿠버네티스 엔진을 활용한 관리형 쿠버네티스 클러스터 사용하기

https://cloud.google.com/kubernetes-engine/docs/deploy-app-cluster
사이트에서 안내에 따라 설치한다.

대략 절차는 아래와 같다

  1. 계정이 없다면 구글에 가입
  2. 구글 클라우드 플랫폼 콘솔에서 프로젝트를 만든다.
  3. 빌링을 활성화한다. (3개월 무료평가판이라 괜찮다)
  4. 쿠버네티스 엔진 api를 활성화시킨다.
  5. 구글 클라우드 sdk를 다운로드하고 설치한다.(쿠버네티스 클러스터를 생성하기 위한 gcloud 명령행 도구가 포함된다.)
  6. gcloud components install kubectl 명령으로 kubectl 명령행 도구를 설치한다.

노드 세 개를 가진 쿠버네티스 클러스터 생성

설치가 완료되면 워커노드 세 개를 가진 쿠버네티스 클러스터를 생성할 수 있다.

$ gcloud container clusters create kubia --num-nodes 3
NAME                                   STATUS   ROLES    AGE     VERSION
gke-kubia-default-pool-c2f41b01-37p5   Ready    <none>   3m10s   v1.22.11-gke.400
gke-kubia-default-pool-c2f41b01-3gd0   Ready    <none>   3m10s   v1.22.11-gke.400
gke-kubia-default-pool-c2f41b01-wgt5   Ready    <none>   3m10s   v1.22.11-gke.400

클러스터 노드를 조회해 클러스터 동작 상태 확인

$ kubectl get nodes

오브젝트에 대한 상세 정보를 보려면 describe 명령을 사용하여
세부 정보를 가져올 수 있다.

모든 노드의 상세 정보 출력

$ kubectl describe node 

특정 노드의 상세 정보 출력

$ kubectl describe node gke-kubia-default-pool-c2f41b01-wgt5

쿠버네티스에 첫 번째 애플리케이션 실행하기

node.js 애플리케이션 구동하는 방법으로 가장 간단한 방법은 kubectl run 명령어를 사용해 JSON 이나 YAML을 사용하기 않고 필요한 모든 구성 요소를 생성하는 방법이다.

이전에 생성해 도커 허브에 푸시한 이미지를 실행해보자

$ kubectl run kubia --image=luksa/kubia --port=8080 

여기선 쿠버네티스에서 디플로이먼트 대신 파드를 생성하도록 했다
(디플로이먼트에 관해서는 추후에 다루도록 하겠다)

파드 조회하기

파드는 컨테이너 그룹이다 kubectl get pods 로 파드를 조회한다.

Pending 상태에서 파드가 할당된 워커 노드가 컨테이너를 실행하기 전에 컨테이너 이미지를 다운로드하고, 다운로드가 완료되면 Running 상태로 전환된다.

$ kubectl get pods
NAME    READY   STATUS    RESTARTS   AGE
kubia   1/1     Running   0          68s

웹 애플리케이션 접근하기

각 파드는 자체 ip 주소를 가지고 있지만 이 주소는 클러스터 내부에 있으며 외부에는 접근이 불가하다.
외부에서 파드에 접근을 가능하게 하려면 서비스 오브젝트 로드밸런서를 통해 노출해야한다. (서비스도 추후에 자세하게 다룬다.)
로드 밸런서의 퍼블릭 ip를 통해 파드에 연결할 수 있다.

서비스를 생성하기 위해 쿠버네티스에게 앞서 생성한 파드를 노출하도록 명령한다.

$ kubectl expose po kubia --type=LoadBalancer --name kubia-http
service/kubia-http exposed

expose 명령어 출력 결과를 보면 kubia-http 라는 서비스가 표시된다.

서비스는 파드나 노드 같은 오브젝트로 새로 생성된 오브젝트를 볼수 있다.
로드 밸런서의 가동이 완료되면 서비스의 외부 IP 주소가 표시된다.

$ kubectl get svc
NAME         TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)          AGE
kubernetes   ClusterIP      10.36.0.1     <none>          443/TCP          23m
kubia-http   LoadBalancer   10.36.5.126   35.247.77.246   8080:32614/TCP   47s

이제 서비스의 외부 IP와 포트를 통해 파드에 요청을 보낼 수 있다.

$ curl 35.247.77.246:8080
You've hit kubia

애플리케이션이 실행 중인 노드 검사하기

-o wide 옵션을 사용하면 추가 열을 요청할 수 있다.
파드 IP와 파드가 실행중인 노드를 표시한다.

$ kubectl get pods -o wide
NAME    READY   STATUS    RESTARTS   AGE   IP          NODE                                   NOMINATED NODE   READINESS GATES
kubia   1/1     Running   0          10m   10.32.1.9   gke-kubia-default-pool-c2f41b01-37p5   <none>           <none>

kubectl decribe pod kubia 를 사용하면 파드의 상세정보를 보여준다.

$ kubectl describe pod kubia
Name:         kubia
Namespace:    default
Priority:     0
Node:         gke-kubia-default-pool-c2f41b01-37p5/10.138.0.3
Start Time:   Sun, 04 Sep 2022 05:59:34 +0000
Labels:       run=kubia
Annotations:  <none>
Status:       Running
...

애플리케이션 수평확장

보통 레플리케이션컨트롤러는 파드를 복제하고 항상 실행 상태로 만든다
여기서는 파드의 레플리카를 지정하지 않고 레플리케이션컨트롤러 파드하나를 생성해보자.

kubia.yaml

apiVersion: v1
kind: ReplicationController
metadata:
  name: kubia
  labels:
    run: kubia
spec:
  replicas: 1
  selector:
    run: kubia
  template:
    metadata:
      labels:
        run: kubia
    spec:
      containers:
      - name: kubia
        image: luksa/kubia:latest
        ports:
        - containerPort: 8080
          protocol: TCP
      

kubia.yaml 파일을 만들고 kubectl create -f kubia.yaml 명령으로 레플리케이션컨트롤러를 생성한다. rc는 레플리케이션컨트롤러의 줄임말로 아래의 명령어로 조회가 가능하다
(yaml 디스크럽터에 관해서는 다음 챕터에 상세히 다루도록 하겠다.)

$ kubectl get rc
NAME    DESIRED   CURRENT   READY   AGE
kubia   1         1         1       2m1s

기존의 있던 파드를 제거한다.

$ kubectl delete po kubia
pod "kubia" deleted

여기서 kubectl get po 를 조회해보면
레플리케이션컨트롤러로 만들어진 파드가 다시 생성되어있는 것을 볼 수 있다.

$ kubectl get po
NAME          READY   STATUS    RESTARTS   AGE
kubia-lzbwf   1/1     Running   0          2m28s

이제 실행 중인 애플리케이션은 레플리케이션컨트롤러에의해 모니터링되고 실행되고 있다.

의도하는 레플리카 수 늘리기

스케일을 이용하여 파드의 레플리카 수를 늘린다.

$ kubectl scale rc kubia --replicas=3

다음 명령으로 파드가 세 개로 표시되는 것을 볼 수 있다.

$ kubectl get po
NAME          READY   STATUS    RESTARTS   AGE
kubia-b5fxm   1/1     Running   0          66s
kubia-lzbwf   1/1     Running   0          13m
kubia-p8vdx   1/1     Running   0          66s

서비스 호출시 모든 파드가 요청받는지 확인

우리가 이전에 서비스를 통해 외부호출을 하도록 로드밸런싱 설정을 했었다.

실행 중인 애플리케이션이 다수의 인스턴스를 갖기 때문에 서비스 URL를 호출하면
다음 과 같이 무작위로 다른 파드를 호출하고 있는것을 확인할 수 있다.

$ curl 35.247.77.246:8080
You've hit kubia-lzbwf
$ curl 35.247.77.246:8080
You've hit kubia-b5fxm
$ curl 35.247.77.246:8080
You've hit kubia-b5fxm
$ curl 35.247.77.246:8080
You've hit kubia-p8vdx

🧨 도커와 쿠버네티스의 기본적인 명령어들을 살펴봤다.
다음 챕터에서는 파드에 집중적으로 탐구해보자

profile
노옵스를향해

0개의 댓글