Gurumee 2021. 8. 5. 07:28
반응형

이 문서는 인프런 강의 "데브옵스를 위한 쿠버네티스 마스터"을 듣고 작성되었습니다. 최대한 요약해서 강의 내용을 최소로 하는데 목표를 두고 있어서, 더 친절하고 정확한 내용을 원하신다면 강의를 구매하시는 것을 추천드립니다. => 강의 링크

쿠버네티스 네트워크 (1) Pod - Container 통신

일반적으로 컨테이너 간 통신을 위한 도커 네트워크 구조는 다음과 같다.

출처: 인프런 강의 Devops를 위한 쿠버네티스 마스터 

각 컨테이너는 veth라는 가상의 네트워크 인터페이스를 통해서 통신을 한다. 반면에, 쿠버네티스에서 컨테이너 간 통신 구조는 살짝 다르다.

출처: 인프런 강의 Devops를 위한 쿠버네티스 마스터 

하나의 veth 가상 네트워크 인터페이스에 여러 컨테이너가 연결되어 있다. 그리고 pause라는 녀석이 옆에 붙어서 이들 통신을 지원해준다. VM에 다음을 입력해보자.

$ sudo docker ps | grep pause
7cec7bbcfd41   k8s.gcr.io/pause:3.4.1   "/pause"                 3 minutes ago   Up 3 minutes             k8s_POD_weave-net-qr5v6_kube-system_52d850d7-c8e4-4b75-93c5-2dd97237b818_8
55878c1c9fbe   k8s.gcr.io/pause:3.4.1   "/pause"                 3 minutes ago   Up 3 minutes             k8s_POD_kube-proxy-hvpz5_kube-system_676e7f6d-825c-43b6-92ea-a1b891092eb4_8
e149257efdfe   k8s.gcr.io/pause:3.4.1   "/pause"                 3 minutes ago   Up 3 minutes             k8s_POD_kube-controller-manager-master_kube-system_683f32b0119799727621446455e8d131_8
ee74476df7aa   k8s.gcr.io/pause:3.4.1   "/pause"                 3 minutes ago   Up 3 minutes             k8s_POD_kube-apiserver-master_kube-system_4497338b493c596567d3c3eb86085559_8
5b7c5e79e66a   k8s.gcr.io/pause:3.4.1   "/pause"                 3 minutes ago   Up 3 minutes             k8s_POD_etcd-master_kube-system_d0eb798391c9389c9721c4631c28dc9a_8
3ec62d452070   k8s.gcr.io/pause:3.4.1   "/pause"                 3 minutes ago   Up 3 minutes             k8s_POD_kube-scheduler-master_kube-system_35ae2ec46407146c0fe6281c2c3292ce_8

 

수 많은 pause가 이미 떠 있는 것을 알 수 있다. 이 puase들은 kube-apiserver, kube-scheduler-master 등의 컴포넌트에 붙어서 네트워크 통신을 지원한다. 마스터 노드에 있는 pod들을 한 번 확인해보자.

$ kubectl get pod --all-namespaces -o wide | grep master
kube-system   etcd-master                      1/1     Running   8          25d   10.0.2.15   master   <none>           <none>
kube-system   kube-apiserver-master            1/1     Running   8          25d   10.0.2.15   master   <none>           <none>
kube-system   kube-controller-manager-master   1/1     Running   8          25d   10.0.2.15   master   <none>           <none>
kube-system   kube-proxy-hvpz5                 1/1     Running   8          25d   10.0.2.15   master   <none>           <none>
kube-system   kube-scheduler-master            1/1     Running   8          25d   10.0.2.15   master   <none>           <none>
kube-system   weave-net-qr5v6                  2/2     Running   17         25d   10.0.2.15   master   <none>           <none>

 

이 중 apiserver 관련만 추출해서 보자.

$ sudo docker ps | grep "apiserver"
58bc8ecf485a   106ff58d4308             "kube-apiserver --ad…"   9 minutes ago   Up 9 minutes                           k8s_kube-apiserver_kube-apiserver-master_kube-system_4497338b493c596567d3c3eb86085559_8
ee74476df7aa   k8s.gcr.io/pause:3.4.1   "/pause"                 9 minutes ago   Up 9 minutes                           k8s_POD_kube-apiserver-master_kube-system_4497338b493c596567d3c3eb86085559_8

이렇게 각 컴포넌트를 수행하는 pod과 옆에 붙어서 컨테이너 간 통신을 지원하는 pause pod이 같이 떠 있는 것을 확인할 수 있다.

쿠버네티스 네트워크 (2) Pod - Pod 통신

쿠버네티스에서 pod끼리의 통신은 CNI(Container Network Interface) 플러그인을 통해서 이루어진다. 다음은 우리가 함께 설치한 Weavenet의 구조이다.

출처: 인프런 강의 Devops를 위한 쿠버네티스 마스터 

이를 확인하기 위해서는 VM에서 다음을 입력한다.

$ sudo netstat -antp | grep weave
tcp        0      0 127.0.0.1:6784          0.0.0.0:*               LISTEN      4229/weaver         
tcp        0      0 10.0.2.15:43560         10.96.0.1:443           ESTABLISHED 4159/weave-npc      
tcp6       0      0 :::6781                 :::*                    LISTEN      4159/weave-npc      
tcp6       0      0 :::6782                 :::*                    LISTEN      4229/weaver         
tcp6       0      0 :::6783                 :::*                    LISTEN      4229/weaver         
tcp6       0      0 10.0.2.15:6783          10.0.2.5:54483          ESTABLISHED 4229/weaver         
tcp6       0      0 10.0.2.15:6783          10.0.2.4:37053          ESTABLISHED 4229/weaver

 

위 명령어는 weavenet에 통하는 네트워크 입출력을 보여준다. 자세히 보면 master node(10.0.2.15)에서 slave node들(10.0.2.4, 10.0.2.5)로 통신하는 것을 확인할 수 있다. 여기서 weaver의 노드 ip/port 확인해보자.

$ ps -eaf | grep 4229
root        4229    4090  0 18:48 ?        00:00:01 /home/weave/weaver --port=6783 --datapath=datapath --name=5a:cd:9a:0c:b3:54 --http-addr=127.0.0.1:6784 --metrics-addr=0.0.0.0:6782 --docker-api= --no-dns --db-prefix=/weavedb/weave-net --ipalloc-range=10.32.0.0/12 --nickname=master --ipalloc-init consensus=2 --conn-limit=200 --expect-npc --no-masq-local 10.0.2.4 10.0.2.5
gurumee    13287    4862  0 19:06 pts/0    00:00:00 grep --color=auto 4229

 

역시 master -> slave 통신을 확인할 수 있다. 한 가지 더 알아둘 것은 이 CNI 플러그인 역시 pod으로 구성되어 동작한다는 것이다. 터미널에 다음을 입력한다.

$ sudo docker ps | grep weave
21216183cb68   7f92d556d4ff             "/usr/bin/launch.sh"     19 minutes ago   Up 19 minutes             k8s_weave-npc_weave-net-qr5v6_kube-system_52d850d7-c8e4-4b75-93c5-2dd97237b818_8
978cef952fea   df29c0a4002c             "/home/weave/launch.…"   19 minutes ago   Up 19 minutes             k8s_weave_weave-net-qr5v6_kube-system_52d850d7-c8e4-4b75-93c5-2dd97237b818_9
7cec7bbcfd41   k8s.gcr.io/pause:3.4.1   "/pause"                 19 minutes ago   Up 19 minutes             k8s_POD_weave-net-qr5v6_kube-system_52d850d7-c8e4-4b75-93c5-2dd97237b818_8

 

여기서 weave-netdaemon-set이라는 리소스로 구성되어 있다. 자세한 설명을 보려면 다음을 입력해보자.

$ kubectl get ds weave-net -n kube-system -o yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  annotations:
    cloud.weave.works/launcher-info: |-
      {
        "original-request": {
          "url": "/k8s/v1.16/net.yaml?k8s-version=Q2xpZW50IFZlcnNpb246IHZlcnNpb24uSW5mb3tNYWpvcjoiMSIsIE1pbm9yOiIyMSIsIEdpdFZlcnNpb246InYxLjIxLjIiLCBHaXRDb21taXQ6IjA5MmZiZmJmNTM0MjdkZTY3Y2FjMWU5ZmE1NGFhYTA5YTI4MzcxZDciLCBHaXRUcmVlU3RhdGU6ImNsZWFuIiwgQnVpbGREYXRlOiIyMDIxLTA2LTE2VDEyOjU5OjExWiIsIEdvVmVyc2lvbjoiZ28xLjE2LjUiLCBDb21waWxlcjoiZ2MiLCBQbGF0Zm9ybToibGludXgvYW1kNjQifQpTZXJ2ZXIgVmVyc2lvbjogdmVyc2lvbi5JbmZve01ham9yOiIxIiwgTWlub3I6IjIxIiwgR2l0VmVyc2lvbjoidjEuMjEuMiIsIEdpdENvbW1pdDoiMDkyZmJmYmY1MzQyN2RlNjdjYWMxZTlmYTU0YWFhMDlhMjgzNzFkNyIsIEdpdFRyZWVTdGF0ZToiY2xlYW4iLCBCdWlsZERhdGU6IjIwMjEtMDYtMTZUMTI6NTM6MTRaIiwgR29WZXJzaW9uOiJnbzEuMTYuNSIsIENvbXBpbGVyOiJnYyIsIFBsYXRmb3JtOiJsaW51eC9hbWQ2NCJ9Cg==",
          "date": "Sat Jul 03 2021 09:55:33 GMT+0000 (UTC)"
        },
        "email-address": "support@weave.works"
      }
    deprecated.daemonset.template.generation: "1"
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"DaemonSet","metadata":{"annotations":{"cloud.weave.works/launcher-info":"{\n  \"original-request\": {\n    \"url\": \"/k8s/v1.16/net.yaml?k8s-version=Q2xpZW50IFZlcnNpb246IHZlcnNpb24uSW5mb3tNYWpvcjoiMSIsIE1pbm9yOiIyMSIsIEdpdFZlcnNpb246InYxLjIxLjIiLCBHaXRDb21taXQ6IjA5MmZiZmJmNTM0MjdkZTY3Y2FjMWU5ZmE1NGFhYTA5YTI4MzcxZDciLCBHaXRUcmVlU3RhdGU6ImNsZWFuIiwgQnVpbGREYXRlOiIyMDIxLTA2LTE2VDEyOjU5OjExWiIsIEdvVmVyc2lvbjoiZ28xLjE2LjUiLCBDb21waWxlcjoiZ2MiLCBQbGF0Zm9ybToibGludXgvYW1kNjQifQpTZXJ2ZXIgVmVyc2lvbjogdmVyc2lvbi5JbmZve01ham9yOiIxIiwgTWlub3I6IjIxIiwgR2l0VmVyc2lvbjoidjEuMjEuMiIsIEdpdENvbW1pdDoiMDkyZmJmYmY1MzQyN2RlNjdjYWMxZTlmYTU0YWFhMDlhMjgzNzFkNyIsIEdpdFRyZWVTdGF0ZToiY2xlYW4iLCBCdWlsZERhdGU6IjIwMjEtMDYtMTZUMTI6NTM6MTRaIiwgR29WZXJzaW9uOiJnbzEuMTYuNSIsIENvbXBpbGVyOiJnYyIsIFBsYXRmb3JtOiJsaW51eC9hbWQ2NCJ9Cg==\",\n    \"date\": \"Sat Jul 03 2021 09:55:33 GMT+0000 (UTC)\"\n  },\n  \"email-address\": \"support@weave.works\"\n}"},"labels":{"name":"weave-net"},"name":"weave-net","namespace":"kube-system"},"spec":{"minReadySeconds":5,"selector":{"matchLabels":{"name":"weave-net"}},"template":{"metadata":{"labels":{"name":"weave-net"}},"spec":{"containers":[{"command":["/home/weave/launch.sh"],"env":[{"name":"HOSTNAME","valueFrom":{"fieldRef":{"apiVersion":"v1","fieldPath":"spec.nodeName"}}},{"name":"INIT_CONTAINER","value":"true"}],"image":"docker.io/weaveworks/weave-kube:2.8.1","name":"weave","readinessProbe":{"httpGet":{"host":"127.0.0.1","path":"/status","port":6784}},"resources":{"requests":{"cpu":"50m","memory":"100Mi"}},"securityContext":{"privileged":true},"volumeMounts":[{"mountPath":"/weavedb","name":"weavedb"},{"mountPath":"/host/var/lib/dbus","name":"dbus"},{"mountPath":"/host/etc/machine-id","name":"machine-id","readOnly":true},{"mountPath":"/run/xtables.lock","name":"xtables-lock"}]},{"env":[{"name":"HOSTNAME","valueFrom":{"fieldRef":{"apiVersion":"v1","fieldPath":"spec.nodeName"}}}],"image":"docker.io/weaveworks/weave-npc:2.8.1","name":"weave-npc","resources":{"requests":{"cpu":"50m","memory":"100Mi"}},"securityContext":{"privileged":true},"volumeMounts":[{"mountPath":"/run/xtables.lock","name":"xtables-lock"}]}],"dnsPolicy":"ClusterFirstWithHostNet","hostNetwork":true,"initContainers":[{"command":["/home/weave/init.sh"],"image":"docker.io/weaveworks/weave-kube:2.8.1","name":"weave-init","securityContext":{"privileged":true},"volumeMounts":[{"mountPath":"/host/opt","name":"cni-bin"},{"mountPath":"/host/home","name":"cni-bin2"},{"mountPath":"/host/etc","name":"cni-conf"},{"mountPath":"/lib/modules","name":"lib-modules"},{"mountPath":"/run/xtables.lock","name":"xtables-lock"}]}],"priorityClassName":"system-node-critical","restartPolicy":"Always","securityContext":{"seLinuxOptions":{}},"serviceAccountName":"weave-net","tolerations":[{"effect":"NoSchedule","operator":"Exists"},{"effect":"NoExecute","operator":"Exists"}],"volumes":[{"hostPath":{"path":"/var/lib/weave"},"name":"weavedb"},{"hostPath":{"path":"/opt"},"name":"cni-bin"},{"hostPath":{"path":"/home"},"name":"cni-bin2"},{"hostPath":{"path":"/etc"},"name":"cni-conf"},{"hostPath":{"path":"/var/lib/dbus"},"name":"dbus"},{"hostPath":{"path":"/lib/modules"},"name":"lib-modules"},{"hostPath":{"path":"/etc/machine-id","type":"FileOrCreate"},"name":"machine-id"},{"hostPath":{"path":"/run/xtables.lock","type":"FileOrCreate"},"name":"xtables-lock"}]}},"updateStrategy":{"type":"RollingUpdate"}}}
  creationTimestamp: "2021-07-03T09:55:33Z"
  generation: 1
  labels:
    name: weave-net
  name: weave-net
  namespace: kube-system
# ...

쿠버네티스 네트워크 (3) Pod - Svc 통신

아래 그림은 podservice가 통신을 나타내는 구조이다.

출처: 인프런 강의 Devops를 위한 쿠버네티스 마스터 

service 생성 시 ClusterIP를 할당 받으면 iptables에 적용한다. 그래서 각 pod으로 통신을 연결해줄 수 있다. 쿠버네티스netfilter를 통해 2-7계층까지 네트워크 통신을 지원한다.  한 번 이를 확인해보자. 터미널에 다음을 입력한다.

$ kubectl get svc --all-namespaces
NAMESPACE     NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
default       kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP                  3d
kube-system   kube-dns     ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   25d

 

"CLUSTER-IP" 대역대인 10.96.x.xservice 리소스가 사용하는 대역이다. 이 대역대의 iptables를 확인해보자.

$ sudo iptables -S -t nat | grep 10.96 
# 53은 DNS 포트
-A KUBE-SERVICES -d 10.96.0.10/32 -p tcp -m comment --comment "kube-system/kube-dns:dns-tcp cluster IP" -m tcp --dport 53 -j KUBE-SVC-ERIFXISQEP7F7OF4
-A KUBE-SERVICES -d 10.96.0.10/32 -p tcp -m comment --comment "kube-system/kube-dns:metrics cluster IP" -m tcp --dport 9153 -j KUBE-SVC-JD5MR3NA4I4DYORP
-A KUBE-SERVICES -d 10.96.0.1/32 -p tcp -m comment --comment "default/kubernetes:https cluster IP" -m tcp --dport 443 -j KUBE-SVC-NPX46M4PTMTKRN6Y
-A KUBE-SERVICES -d 10.96.0.10/32 -p udp -m comment --comment "kube-system/kube-dns:dns cluster IP" -m udp --dport 53 -j KUBE-SVC-TCOU7JCQXEZGVUNU

 

여러 개가 체인처럼 엮여 있는 것을 볼 수 있는데, 그냥 이는 내부 구현이고 중요한 것은 pod에서 service를 호출하게 되면, 쿠버네티스에 존재하는 내부 DNS 시스템에 의해서 연결된 다른 pod이 호출된다는 것이다.

쿠버네티스 네트워크 (4) 외부 물리 클라이언트 통신

다음은 외부 클라이언트에서 서비스를 호출했을 때 나타나는 플로우이다.

출처: 인프런 강의 Devops를 위한 쿠버네티스 마스터 

클라이언트에서 LoadBalancer를 통해 호출하게 되면 그 안에 route table에 의해서 node로, 그 후 안에 네트워크 인터페이스(eth0)와 netfilter를 통해서 service가 호출되고 그 후 pod이 호출된다. 외부에서는 node와 연결되고 node 내에서는 pod-svc의 플로우가 동작하는 것이다.

쿠버네티스 네트워크 (5) CoreDNS

pod에서 service를 호출할 수 있는 이유는 바로 CoreDNS라는 쿠버네티스의 DNS 서버 역할을 하는 컴포넌트가 있기 때문이다. 

 

CoreDNS는 쿠버네티스 클러스터의 DNS 서버 역할을 수행한다. 역시 pod으로 구성되어서 동작하고 있으며. 각 미들웨어를 통해 로깅, 캐시, 쿠버네티스 질의하는 기능을 수행한다.

 

일반적으로 service를 다음과 같이 호출할 수 있다.

<svc_name>.<ns_name>.svc.cluster.local 형식으로 도메인 획득 가능

 

이에 대한 실습을 진행한다. 먼저 "gurumee"라는 네임스페이스를 생성한다.

 

src/ch09/k8s/coredns-ns-gurumee.yaml)

apiVersion: v1
kind: Namespace
metadata:
  creationTimestamp: null
  name: gurumee
spec: {}
status: {}

 

그 후, Deployment를 생성한다.

 

src/ch09/k8s/coredns-simple-app-dep.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: simple-app-dep
  namespace: gurumee
  labels:
    app: simple-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: simple-app
  template:
    metadata:
      labels:
        app: simple-app
    spec:
      containers:
        - name: simple-app
          image: gurumee92/simple-app:v1
          ports:
            - containerPort: 8080

 

그 다음 ClusterIP 형태로 Service를 통해 Deployment를 연결해준다.

 

src/ch09/k8s/coredns-simple-app-svc.yaml

apiVersion: v1
kind: Service
metadata:
  name: simple-app-svc
  namespace: gurumee
spec:
  ports:
    - port: 8080
      targetPort: 8080
  selector:
    app: simple-app

 

그 후 nginx를 기반으로 pod 1개를 실행한다.

$ kubectl run nginx --image=nginx

 

그 후 그 pod에서 curlsvc_name.ns_name:8080으로 호출해보자.

$ kubectl exec -it nginx -- curl simple-app-svc.gurumee:8080
Hello World v1 

 

이렇게 떴다면 성공이다.

쿠버네티스 스토리지 (1) 볼륨

"볼륨"은 컨테이너가 외부 스토리지에 액세스하고 공유하는 방법이다. 다음과 같은 방법이 있다.

  • 임시 볼륨 : emptyDir (컨테이너 볼륨 공유)
  • 로컬 볼륨 : hostPath, local (노드 관리 목적)
  • 네트워크 볼륨 : NFS, glusterFS (외부 자원 공유 목적)
  • 네트워크 볼륨 (클라우드) : awsEBS, gcePersistentDisk

이외에도 pvc, configMap 등이 있다.

쿠버네티스 스토리지 (2) EmptyDir

볼륨 EmptyDir을 통해 pod간 볼륨을 공유하게끔 만들 수 있다. 이제 다음과 같이 스크립트를 하나 작성한다.

 

src/ch09/app/count.sh

#!/bin/sh
trap "exit" SIGINT
mkdir /var/htdocs

SET=$(seq 0 99999)
for i in $SET
do
  echo "RUNNING loop seq $i" > /var/htdocs/index.html
  sleep 10
done

 

그리고 build 하기 전에 chmod 777 명령어를 주어서 실행 파일 권한을 주자 Dockerfile을 다음과 같이 만든다.

 

src/ch09/app/Dockerfile

FROM busybox:latest

ADD count.sh /bin/count.sh

ENTRYPOINT /bin/count.sh

 

그 후 자신의 ID로 이미지를 만들어서 push한다. 그 후 다음과 같이 리소스를 생성한다.

 

src/ch09/k8s/volume-empty-dir.yaml

...
apiVersion: v1
kind: Pod
metadata:
   name: volume-empty-dir
spec:
   containers:
      - image: gurumee92/count
        name: html-generator
        volumeMounts:
           - mountPath: /var/htdocs/
             name: html
      - image: httpd
        name: web-server
        volumeMounts:
           - mountPath: /usr/local/apache2/htdocs
             name: html
             readOnly: true
        ports:
           - containerPort: 80
   volumes:
      - name: html
        emptyDir: {}

 

그 후 nginx를 기반으로 pod 1개를 실행한다.

$ kubectl run nginx --image=nginx

 

그러면 다음의 pod들이 생성되어진다.

$ kubectl get pod -o wide
NAME               READY   STATUS    RESTARTS   AGE     IP          NODE     NOMINATED NODE   READINESS GATES
nginx              1/1     Running   0          2m55s   10.32.0.3   slave2   <none>           <none>
volume-empty-dir   2/2     Running   0          6m34s   10.32.0.2   slave2   <none>           <none>

 

이제 nginx 포드에서 volume-empty-dir 포드로 curl을 요청해보자.

# 10.32.0.2 = volume-empty-dir IP
$ kubectl exec -it nginx -- curl 10.32.0.2 
RUNNING loop seq 48

 

이제 만들어진지 480초가 지났다는 의미이다. 10초 간격으로 계속 curl을 요청하면 "seq" 값이 변하는 것을 확인할 수 있다.

쿠버네티스 스토리지 (3) Hostpath

hostPath 볼륨은 노드와 포드간 데이터 공유를 위해서 만들어지는 볼륨이다. 해당 노드의 파일 시스템에 있는 파일 혹은 디렉토리를 지정하기 때문에 노드에 떠 있는 포드들하고만 연결이 가능하다.

 

주로 노드의 모니터링을 위해서 많이 사용된다. 이제 실습을 진행해보자. 먼저 워커 노드에서 다음을 명령한다.

## sudo 권한 획득 
$ sudo -i

## 디렉토리 생성
# mkdir -p /var/htdocs

# echo "$HOSTNAME" > /var/htdocs/index.html

 

그 후 다음 리소스를 생성한다.

 

src/ch09/volume-hostpath.yaml

apiVersion: v1
kind: Pod
metadata:
  name: volume-hostpath
spec:
  containers:
    - image: httpd
      name: web-server
      volumeMounts:
        - mountPath: /usr/local/apache2/htdocs
          name: html
          readOnly: true
      ports:
        - containerPort: 80
  volumes:
    - name: html
      hostPath:
        path: /var/htdocs
        type: Directory

 

그 다음 아래 명령어를 입력하여 포드가 어디 노드에 생성되었는지 확인한다.

$ kubectl get pod -o wide -w
NAME               READY   STATUS    RESTARTS   AGE   IP          NODE     NOMINATED NODE   READINESS GATES
volume-hostpath    1/1     Running   0          15s   10.40.0.3   slave1   <none>           <none>

 

워커 노드 1("slave1")에 포드가 위치하고 있다. 이제 이 포드를 접속할 수 있도록 port-forward로 포트를 개방한다.

$ kubectl port-forward hostpath-http 8888:80
Forwarding from 127.0.0.1:8888 -> 80
Forwarding from [::1]:8888 -> 80
Handling connection for 8888

 

이제 새 탭을 열어 다음을 입력한다.

$ curl localhost:8888
slave1

"slave1"이 뜨는 것을 확인할 수 있다.

728x90
반응형