로컬 쿠버네티스에 ingress-nginx 사용방법
1. ingress-nginx 개요
인그레스를 사용하면 L7의 웹 요청을 해석해서 단일 IP, 단일 포트로 다수의 도메인과 서비스로 연결할 수 있음
이 방법을 사용하면 웹페이지의 도메인은 같지만 다른 앱을 사용하는 것도 가능하게 한다
하지만 쿠버네티스에서 기본적으로 지원하는 인그레스 오브젝트는 클라우드 환경이 아니면 사용할 수 없다
클라우드에서 인그레스를 생성하면 외부에 게이트웨이를 생성하고 각 기능에 맞게 서비스에 연결한다
GCP의 경우에는 외부 게이트웨이에 L7 규칙이 적용돼 있다
이 포스트에 있는 nginx-ingress를 사용해보기 전에 GCP에서 제공하는 ingress를 한번 써보시길 권장한다
HTTP(S) 부하 분산용 GKE 인그레스
여기서는 로컬에서 인그레스를 사용할 수 있는 ingress-nginx를 설치하고 쿠버네티스에 포드 형태로 띄워서 설정하는 방법을 알아본다
nginx-ingress를 포드로 떠있으면서 다시 서비스로 연결할 수 있는 역할을 수행한다
Enterprise-grade application delivery for Kubernetes
그림출처: https://www.nginx.com/products/nginx/kubernetes-ingress-controller/
깃헙 사이트에서 nginx-ingress에 대한 예제를 몇개 제공하고 있다
그 중 가장 기본적인 예제를 분석하고 사용하도록 한다
https://github.com/kubernetes/ingress-nginx/blob/master/deploy/static/provider/baremetal/deploy.yaml
2. ingress-nginx 예제 분석
예제가 매우 길지만 이런 예제를 분석할 줄 알아야 우리의 환경에서 ingress-nginx가 정확히 어떻게 동작할지 예상할 수 있다
라인 수는 거의 300라인 정도 된다
하나씩 살펴보고 어떤 기능을 가질지 예상해 보자
[namespace]ingress-nginx
첫 번째 오브젝트부터 살펴보자
가장 먼저 네임스페이스를 선언한다
ingress-nginx라는 별도의 네임스페이스를 생성한다
앞으로 선언돼는 모든 오브젝트들은 이 네임스페이스에 할당된다
limitRange 는 yaml의 가장 아랫부분에 있는 오브젝트인데 네임스페이스의 자원할당량을 제한하는 역할을 수행하므로 네임스페이스와 함께 보자
여기서 생성되는 limitRange 는 컨테이너 최소 권장사항만 cpu 100m, 메모리 사용량 90Mi로 정의한다
apiVersion: v1
kind: Namespace
metadata:
name: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
apiVersion: v1
kind: LimitRange
metadata:
name: ingress-nginx
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
limits:
- min:
memory: 90Mi
cpu: 100m
type: Container
[Configmap]nginx-configuration, tcp-services, udp-servies
두 번째는 다수의 confimap이 선언돼 있다
레이블이 세팅돼 있지만 딱히 저장돼있는 키와 값은 없다
각각의 이름은 nginx-configuration, tcp-services, udp-servies 이다
kind: ConfigMap
apiVersion: v1
metadata:
name: nginx-configuration
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
kind: ConfigMap
apiVersion: v1
metadata:
name: tcp-services
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
kind: ConfigMap
apiVersion: v1
metadata:
name: udp-services
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
[ServiceAccount] nginx-ingress-serviceaccount
nginx-ingress 포드에서 사용할 계정을 생성한다
쿠버네티스에서는 실행하는 앱에 권한을 줄 때 서비스 어카운트를 사용한다
서비스 어카운트에 권한을 할당해야하는데 여기서는 클러스터 롤과 롤을 할당한다
다음 코드를 정리하면 다음과 같은 권한을 할당한다
관리자 권한을 부여하지 않는 이유는 최소 권한의 원칙을 따르기 위해서이다
nginx-ingress-serviceaccount 는 다음과 같은 권한을 갖는다
apiVersion: v1
kind: ServiceAccount
metadata:
name: nginx-ingress-serviceaccount
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: nginx-ingress-clusterrole
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- nodes
- pods
- secrets
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- "extensions"
- "networking.k8s.io"
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- "extensions"
- "networking.k8s.io"
resources:
- ingresses/status
verbs:
- update
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
name: nginx-ingress-role
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- configmaps
- pods
- secrets
- namespaces
verbs:
- get
- apiGroups:
- ""
resources:
- configmaps
resourceNames:
# Defaults to "<election-id>-<ingress-class>"
# Here: "<ingress-controller-leader>-<nginx>"
# This has to be adapted if you change either parameter
# when launching the nginx-ingress-controller.
- "ingress-controller-leader-nginx"
verbs:
- get
- update
- apiGroups:
- ""
resources:
- configmaps
verbs:
- create
- apiGroups:
- ""
resources:
- endpoints
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
name: nginx-ingress-role-nisa-binding
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: nginx-ingress-role
subjects:
- kind: ServiceAccount
name: nginx-ingress-serviceaccount
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: nginx-ingress-clusterrole-nisa-binding
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: nginx-ingress-clusterrole
subjects:
- kind: ServiceAccount
name: nginx-ingress-serviceaccount
namespace: ingress-nginx
[Deployment] nginx-ingress-controller
드디어 디플로이먼트이다
디플로이먼트는 포드를 배치한다
nginx-ingress의 역할을 하는 컨테이너를 배치하고 서비스가 동작하도록 만든다
nginx는 nginx의 conf 파일을 수정하면 프록시 서버로 동작한다
여기서는 내부 파일을 사용자가 직접 변경하지 않아도 프록시의 역할을 수행하는데
ingress를 읽는 권한이 있어서 데이터를 스스로 읽고 알맞는 서비스로 연결한다
컨테이너에서 발견할 수 있는 몇가지 특징을 표로 정리한다
구분 | 내용 | 설명 |
---|---|---|
이미지 | quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0 | 커스터마이징된 nginx-ingress 이미지를 사용한다 |
아규먼트 | /nginx-ingress-controller --configmap=$(POD_NAMESPACE)/nginx-configuration --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services --udp-services-configmap=$(POD_NAMESPACE)/udp-services --publish-service=$(POD_NAMESPACE)/ingress-nginx --annotations-prefix=nginx.ingress.kubernetes.io |
앞서 쿠버네티스에 세팅한 컨피그맵들을 전달한다 네임스페이스의 이름은 ingress-nginx로 선언돼있습니다. 아규먼트에 대한 자세한 설명은 다음 링크를 참고하기 바란다 https://kubernetes.github.io/ingress-nginx/user-guide/cli-arguments/ |
시큐리티콘텍스트 | securityContext: allowPrivilegeEscalation: true capabilities: drop: - ALL add: - NET_BIND_SERVICE # www-data -> 101 runAsUser: 101 |
시큐리티콘텍스트는 보안 관련 설정이다 root 권한으로 실행할 수 있도록 허용했고 커널 권한은 모두 드랍하고 1024 이하의 포트를 바인딩할 수 있는 NET_BIND_SERVICE 권한만 갖게 했다 그리고 기본 애플리케이션은 www-data의 권한인 101 권한으로 실행한다 |
포트 | ports: - name: http containerPort: 80 protocol: TCP - name: https containerPort: 443 protocol: TCP |
포트는 80과 443번을 사용한다 |
라이브네스/레디네스 프로브 | livenessProbe: (readinessProbe도 동일) failureThreshold: 3 httpGet: path: /healthz port: 10254 scheme: HTTP initialDelaySeconds: 10 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 10 |
포드가 살아있는지 준비돼있는지 체크하는 루틴이다 10254포트로 웹 요청했을때 400미만의 요청이 오면 정상 서비스 가능한 것으로 본다 |
라이프사이클 | lifecycle: preStop: exec: command: - /wait-shutdown |
쿠버네티스도 컨테이너에 라이프사이클 훅을 제공한다 컨테이너가 생성된 직후에 실행(PostStart)되거나 컨테이너가 종료되기 직전(PreStop)에 실행할 내용을 지정할 수 있는데 여기서는 포드가 종료될 때 실행할 명령으로 wait-shutdown을 실행한다 |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-ingress-controller
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
template:
metadata:
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
annotations:
prometheus.io/port: "10254"
prometheus.io/scrape: "true"
spec:
# wait up to five minutes for the drain of connections
terminationGracePeriodSeconds: 300
serviceAccountName: nginx-ingress-serviceaccount
nodeSelector:
kubernetes.io/os: linux
containers:
- name: nginx-ingress-controller
image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0
args:
- /nginx-ingress-controller
- --configmap=$(POD_NAMESPACE)/nginx-configuration
- --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
- --udp-services-configmap=$(POD_NAMESPACE)/udp-services
- --publish-service=$(POD_NAMESPACE)/ingress-nginx
- --annotations-prefix=nginx.ingress.kubernetes.io
securityContext:
allowPrivilegeEscalation: true
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
# www-data -> 101
runAsUser: 101
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
ports:
- name: http
containerPort: 80
protocol: TCP
- name: https
containerPort: 443
protocol: TCP
livenessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 10
readinessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 10
lifecycle:
preStop:
exec:
command:
- /wait-shutdown
이렇게 생성된 컨테이너는 스스로 인그레스를 읽을 수 있는 기능을 가지고 있으며 서비스 ingress-nginx를 통해서 사용된다라고 예상해볼 수 있다
또한 80포트와 443포트를 동시에 제공하고 있다
3. http-go 서비스 설치
이제 이 ingress-nginx를 직접 쿠버네티스에 설치하고 ingress가 잘 실행되는지 테스트해보자
가장 먼저 할일은 웹서비스를 하나 띄우고 그 서비스가 잘 서비스되는지 테스트하는 ingress는 그 다음에 설치한다
http-go는 go로 작성했으며 8080포트로 웹서비스를 하는 간단한 이미지이다
서비스는 NodePort로 열어준다
$ kubectl create deployment http-go --image=gasbugs/http-go
deployment.apps/http-go created
$ kubectl expose deployment http-go --port=8080 --type=NodePort
service/http-go exposed
GCP에서는 svc 포트를 확인해서 해당 포트의 방화벽 설정 추가
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
http-go NodePort 10.8.9.35 <none> 8080:31462/TCP 106s
kubernetes ClusterIP 10.8.0.1 <none> 443/TCP 10m
$ gcloud compute firewall-rules create http-go-svc-rule --allow=tcp:31462
Creating firewall...⠹Created [https://www.googleapis.com/compute/v1/projects/freework-gke-test-20201227/global/firewalls/http-go-svc-rule].
Creating firewall...done.
NAME NETWORK DIRECTION PRIORITY ALLOW DENY DISABLED
http-go-svc-rule default INGRESS 1000 tcp:31462 False
테스트를 위해 EXTERNAL-IP 정보 확인
kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
gke-cluster-1-default-pool-3496da67-fh9n Ready <none> 13m v1.16.15-gke.6000 10.128.0.5 34.72.1.248 Container-Optimized OS from Google 4.19.112+ docker://19.3.1
gke-cluster-1-default-pool-3496da67-nlsd Ready <none> 13m v1.16.15-gke.6000 10.128.0.6 35.239.62.20 Container-Optimized OS from Google 4.19.112+ docker://19.3.1
gke-cluster-1-default-pool-3496da67-zfjd Ready <none> 13m v1.16.15-gke.6000 10.128.0.7 35.184.60.185 Container-Optimized OS from Google 4.19.112+ docker://19.3.1
잠시 후 웹서비스가 잘 도는지 확인하기 위해서 curl 명령을 사용한다
$ curl 34.72.1.248:31462
Welcome! http-go-78dfc8fcf5-d2xbb
4. Ingress-nginx 설치
https://github.com/kubernetes/ingress-nginx/blob/master/docs/deploy/index.md
이제 앞서 분석했던 yaml을 사용해 ingress-nginx를 설치한다
분석했던 내용처럼 namespace가 생성되고 configmap 3개, 서비스어카운트에 클러스터롤과 롤 권한이 부여된다
마지막으로 nginx-ingress-controller라는 이름으로 디플로이먼트가 시작된다
https://github.com/kubernetes/ingress-nginx/blob/master/docs/deploy/index.md#bare-metal
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.43.0/deploy/static/provider/baremetal/deploy.yaml
namespace/ingress-nginx created
serviceaccount/ingress-nginx created
configmap/ingress-nginx-controller created
clusterrole.rbac.authorization.k8s.io/ingress-nginx created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx created
role.rbac.authorization.k8s.io/ingress-nginx created
rolebinding.rbac.authorization.k8s.io/ingress-nginx created
service/ingress-nginx-controller-admission created
service/ingress-nginx-controller created # deployment 를 사용할 수 있도록 열어줌
deployment.apps/ingress-nginx-controller created # deployment 를 생성했음
validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission created
serviceaccount/ingress-nginx-admission created
clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
role.rbac.authorization.k8s.io/ingress-nginx-admission created
rolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
job.batch/ingress-nginx-admission-create created
job.batch/ingress-nginx-admission-patch created
ingress-nginx-controller 서비스 확인
ingress 파일을 읽어서 http-go 로 연결해준다
$ kubectl get service/ingress-nginx-controller -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.8.0.3 <none> 80:31170/TCP,443:32188/TCP 3m34s
ingress-nginx 네임스페이스의 포드를 조회해 잘 도는지 확인한다
당연히 지금은 ingress 객체를 만들지 않았기 때문에 포워딩 기능이 실행되고 있지는 않다
$ kubectl get pod -n ingress-nginx
NAME READY STATUS RESTARTS AGE
nginx-ingress-controller-7f74f657bd-m4sjb 1/1 Running 0 99s
함께 만들어진 nginx-ingress-controller의 서비스인 노드포트를 확인한다
여기서 포트는 31042와 30947이다
443 포트는 ingress를 생성했을 때 tls를 쓴 경우에 사용할 수 있다
여기서는 80포트로 접속할 것이니 31042를 사용하면 된다
$ kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-ingress-controller NodePort 10.96.254.175 <none> 80:31042/TCP,443:30947/TCP 56s
5. Ingress 룰 생성
이제 ingress를 생성해 ingress-nginx와 http-go를 연결할 룰을 만들어 준다
다음 그림처럼 룰을 만들어야 외부에서 요청이 왔을 때 인그레스가 http-go로 포워딩해준다
ingress의 룰은 단순하다
도메인과 경로로 규칙을 지정하는데 여기서는 gasbugs.com/hostsname로 ingress에 요청이 들어오면 http-go로 연결해준다
내용을 작성할 때는 다음을 주의해야 합니다
- http-go와 동일한 네임스페이스에 작성해야 함
- 앞서 생성한 서비스 이름이 serviceName과 동일해야 함
- servicePort는 서비스가 동작하는 포트를 의미해야 함
(서비스의 포트와 포드의 포트가 다른 경우에도 서비스 포트를 적는다)
도메인 이름은 gasbugs.com을 사용하고 /hostsname 경로를 사용하도록 만들었기 때문에
반드시 http://gasbugs.com/hostsname으로 요청해야만 http-go로 연결된다
http-go-ingress.yaml 파일 생성
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: http-go-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: gasbugs.com
http:
paths:
- path: /hostname
backend:
serviceName: http-go
servicePort: 8080
kubectl 로 ingress 생성
$ kubectl create -f http-go-ingress.yaml
ingress.extensions/http-go-ingress created
ingress-nginx-controller 서비스를 조회해서 포트 확인 후 방화벽 오픈
$ kubectl get svc -n ingress-nginx ingress-nginx-controller
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.8.0.3 <none> 80:31170/TCP,443:32188/TCP 10m
$ gcloud compute firewall-rules create ingress-svc-rule --allow=tcp:31170
Creating firewall...⠹Created [https://www.googleapis.com/compute/v1/projects/freework-gke-test-20201227/global/firewalls/ingress-svc-rule].
Creating firewall...done.
NAME NETWORK DIRECTION PRIORITY ALLOW DENY DISABLED
ingress-svc-rule default INGRESS 1000 tcp:31170 False
6. 인그레스 정상 동작 테스트
GCP 에서 동작 확인
IP 확인
kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
gke-cluster-1-default-pool-3496da67-fh9n Ready <none> 35m v1.16.15-gke.6000 10.128.0.5 34.72.1.248 Container-Optimized OS from Google 4.19.112+ docker://19.3.1
gke-cluster-1-default-pool-3496da67-nlsd Ready <none> 35m v1.16.15-gke.6000 10.128.0.6 35.239.62.20 Container-Optimized OS from Google 4.19.112+ docker://19.3.1
gke-cluster-1-default-pool-3496da67-zfjd Ready <none> 35m v1.16.15-gke.6000 10.128.0.7 35.184.60.185 Container-Optimized OS from Google 4.19.112+ docker://19.3.1
curl 접속 테스트시 도메인 이름과 URI 가 일치 해야지만 연결을 해주는데 일치하지 않으므로 연결이 실패함
$ curl 34.72.1.248:31170
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>
/etc/hosts
에 도메인 추가
$ sudo vi /etc/hosts
...
34.72.1.248 gasbugs.com
path 의 /hostname
URI 까지 일치 시키면 연결이 성공함
$ curl gasbugs.com:31170/hostname
Welcome! http-go-78dfc8fcf5-d2xbb
local 에서 동작 확인
gasbugs.com의 31042로 접속을 시도해보자
127.0.0.1:31042 로도 요청을 수행한다
127.0.0.1을 직접 요청하는 경우에는 도메인이름이 "127.0.0.1"로 날아가기 때문에 앞서 설정한 룰과 일치하지 않아서 404를 띄운다
$ curl gasbugs.com:31042
curl: (6) Could not resolve host: gasbugs.com
$ curl 127.0.0.1:31042
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.17.8</center>
</body>
</html>
두 요청 모두 제대로된 응답을 못받는다
우리는 도메인을 등록한 적이 없기 때문인데 도메인을 등록해서 해결하기보다는
임시용으로 /etc/hosts에 "127.0.0.1 gasbugs.com"를 추가하도록 한다
$ sudo vim /etc/hosts
127.0.0.1 gasbugs.com
<생략>
다시 요청을 수행한다
여전히 페이지를 못 찾는 모습을 보인다
경로도 정확하게 입력해야 한다
$ curl gasbugs.com:31042
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.17.8</center>
</body>
</html>
이번에는 도메인 이름과 경로를 모두 일치시켜서 질의를 수행하면 정상적으로 응답을 받아오는 모습을 관찰할 수 있다
$ curl gasbugs.com:31042/hostname
Welcome! http-go-78dfc8fcf5-jzmmv
'개발강의정리 > DevOps' 카테고리의 다른 글
[쿠버네티스 어나더 클래스-지상편] 2. 쿠버네티스 무게감 있게 설치하기 (0) | 2023.09.25 |
---|---|
[쿠버네티스 어나더 클래스-지상편] 1. 컨테이너 한방 정리 (0) | 2023.09.25 |
[데브옵스를 위한 쿠버네티스 마스터] 쿠버네티스 환경에서 예제를 활용한 애플리케이션 개발 (0) | 2021.01.22 |
[데브옵스를 위한 쿠버네티스 마스터] 클러스터 유지와 보안, 트러블슈팅 - 클러스터, 애플리케이션 트러블 슈팅 가이드 (0) | 2021.01.22 |
[데브옵스를 위한 쿠버네티스 마스터] 클러스터 유지와 보안, 트러블슈팅 - 네트워크 정책 적용 (0) | 2021.01.22 |
댓글