222. DNS in kubernetes

선수 지식

얼추 배울거

노드에는 파드와 서비스가 있고 각자 노드는 이름과 ip를 가지고 있다. 

노드이름과 ip를 등록한 dns 가 있다.

그거와 별개로 쿠버네티스는 기본적으로 클러스터단에 실행되는 dns가 있다.

이해를 돕기 위해 노드는 신경 쓰지 않고 파드, 서비스 dns 에 집중해보자!

파드 두개와 서비스가 하나 있다.

test 와 web 

 web-service 라는 서비스를 만들었다. 

서비스가 생성되면 쿠버네티스 dns 서비스가 레코드를 생성한다. 

curl http://web-service 로 test에서 web으로 접속 가능하다. 

네임스페이스 처럼

test, web-service 파드 모두 같은 네임스페이스 디폴트 네임스페이스에 존재한다, 

test에서  web-service로 web에 접속할 수 있다. 

default 와 apps 로 분리되어있다고 가정해보자 

url 을 사용할때 네임스페이스 정보도 같이 기입해야한다.

web-service.apps

도메인 네임을 자세히 보면

호스트 네임, 네임스페이스 , 타입이 들어간다. 

마지막으로 어느 클러스터에 포함되는지 root 정보가 필요하다. 

cluster.local 이 루트 도메인이다. 

최종적으로 

web-service.apps.svc.cluster.local 이런식으로 사용 가능하다.

파드의 경우 ip가 .에서 - 로 변경된다. 

10.244.2.5 가 10-244-2-5 가 된다. 

 

다른 네임스페이스에 있다면

네임스페이스가 달라진다.


223. CoreDNS in Kubernetes

ip를 갖는 파드 2개가 있다. 

파드의 etc/hosts 파일을 보면 도메인 네임이 등록되어있다. 

파드가 많아지면 /etc/hosts 폴더에 등록하는 것도 불가능하니까 dns에 등록한다. 

etc/resolve.conf 파일에 네임 서버를 등록한다. 

파드가 등록될때마다 dns 등록함으로서 도메인 네임으로 접속 가능하게 한다. 

쿠버네티스에서 dns는 이름으로 저장하는 것이 아닌 .을 -로 표현해서 저장한다.

10-244-2-5 

 

CoreDNS 

쿠버네티스에서 coredns 가 도와준다. 

이중화를 위해 레플리카셋에 두개 파드로 구현된다. ( 디플로이먼트 안에 레플리카셋) 

 

coreDNS는 corefile 이라는 구성 파일을 필요로 한다.

/etc/coreDNS/Corefile

에러를 담당하는 여러 플러그인이 존재한다,

kubernetes 부분에 탑레벨 도메인이 들어간다. cluster.local

configmap 으로도 coredns는 존재한다. 

coredns는 kube-dns 라는 서비스와도 연결되어 있어 클러스터내에서 사용가능하다. 

파드의 네임서버를 등록할때 이 서비스 ip를 등록한다.

kube-dns 10.96.0.10 

 

var/lib/kubelet/config.yaml 파일을 통해서 dns의 ip 와 도메인을 확인할 수 있다. 

이제 파드에서 모두 사용가능

host 명령으로 도메인 확인 가능

resolv.conf 파일에 온갖 이름이 다 있다.

 


224. Practice Test - Explore DNS

1. Identify the DNS solution implemented in this cluster

coreDNS 를 사용

 

2. How many pods of the DNS Server are deployed?

2개 

 

3. What is the name of the service created for accessing CoreDNS? 

kube-dns

 

4. what is the IP of the CoreDNS server that should be configured on PODs to resolve services?

서비스 클러스터 ip 10.96.0.10

 

5. where is the configuration file located for configuring the CoreDNS service?

deployments 를 통해 확인

/etc/coredns/Corefile

 

6. How is the Corefile passed into the CoreDNS POD? 

pulled from git
Stored on the kube master
Configured as a ConfigMap object
Corefile comes built-in with CoreDNS pod

config map 

config map 형식으로 넘겨진다. 

 

7. what is the name of the ConfigMap object created for corefile? 

 coredns

 

8. what is the root domain/zone configured for this kubernetes cluster?

cluster.local

 

9. we have deployed a set of PODs and Services in the default and payroll namespaces. Inspect them and go to the next question.'

 

10. What name can be used to access the hr web server from the test Application?

You can execute a curl command on the test pod to test. Alternatively, the test Application also has a UI. Access it using the tab at the top of your terminal named test-app.

 

 

test
webserver

web-service 로 접속

 

 

11. which of the names CANNOT be used to access the HR service from the test pod? 

web-service.default
web-service.default.pod
web-service.default.svc
web-service

web-service.default.pod 안됨 

 

12. Which of the below name can be used to access the payroll service from the test application?

 

web-service.payroll

 

13. Which of the below name CANNOT be used to access the payroll service from the test application?

web-service.payroll.svc
web-service.payroll.svc.cluster.local
web-service.payroll.svc.cluster
web-service.payroll

14.

We just deployed a web server - webapp - that accesses a database mysql - server. However the web server is failing to connect to the database server. Troubleshoot and fix the issue.

 

They could be in different namespaces. First locate the applications. The web server interface can be seen by clicking the tab Web Server at the top of your terminal.

 

호스트 네임을 변경한다. mysql.payroll

그냥 서비스

payroll 네임스페이스에는 mysql 이 존재한다.

 

15. From the hr pod nslookup the mysql service and redirect the output to a file /root/CKA/nslookup.out

kubectl exec -it hr -- nslookup mysql.payroll > /root/CKA/nslookup.out

 


226. Ingress

online shop 을 꾸린다고 가정

어느 wear 파드에서든 접근 가능하게 하려고 mysql 서비스 생성 cluster ip

외부로 나가는 서비스 wear-service 생성 nodeport

 

mysql 과 외부에 연결 가능

port 38080

http://node-ip:38080 으로 접속 가능하다.

node ip를 안쓰기 위해 dns 가 필요하고

포트 번호를 안쓰게 하기 위해 proxy 서버가 필요하다. 80 으로 들어오는거 -> 38080 으로

gcp 클라우드 플랫폼을 사용하면 로드 밸런서를 사용할 수 있다. 

gcp는 자동으로 로드 밸런서를 설치한다. 

gcp load-balancer

gcp는 외부 ip를 갖는다. 

my-online-store.com으로 사용 가능하다.

 

사업이 확장하면서 watch 페이지를 추가하고 싶다면?

이렇게 디플로이먼트, 서비스, 포트를 추가해야겠지?

새로운 로드밸런서는 새로운 ip를 요구한다.

어떻게 url 을 리다이렉트하는가?

/apparel, /video 처럼 로드 밸러서가 필요하다.

보안을 위해 ssl 도 고려해야한다.

쿠버네티스에서 이 모든 걸 한번에 다루면 어떨까?

Ingress

인그레스를 통해 한 url을 이용해 다르게 라우트 할 수 있음.

인그레스도 외부에서 접근 용이하게 하기 위해 서비스가 필요하다.nodeport 38080

한번만 구성하면 된다.

인그레스 컨트롤러와 인그레스 리소스가 필요하다.

인그레스 컨트롤러는 쿠버네티스에 기본 탑재 되어있지 않다. 따로 설치해야한다.

 

 

인그레스 컨트롤러 직접 선택해야한다. 

nginx 를 사용해보자

nginx 컨트롤러를 디플로이먼트를 통해 배포된다.

configmap 객체를 만들어서 nginx 구성을 넘겨야한다.

파드네임과 네임스페이스도 구성해야한다.

포트 정보

외부로 노출 시키기 위한 서비스도 생성한다.

서비스 어카운트도 필요

 

인그레스를 사용하기 위해 디플로이먼트, 서비스, 컨피그맵, auth 가 필요하다. 

 

인그레스 리소스 

여러가지 규칙들이 저장됨.

인그레스 리소스 예시 

 

backend 도 명시 

서비스로 라우팅한다. 

인그레스 생성과 확인

여러 케이스에 따라 다르게 라우팅 할 수 있다.

예시들

인그레스 리소스를 구성해보자

싱글 도메인 네임을 추가한다. 

www.my-online-store.com  에 진입할 수 있게 한다.

 

/wear 

/watch 

서비스로 연결 시킨다.

인그레스를 확인하면 두개의 url 이 있다. 

default 백엔드가 존재한다. 

default-http-backend 서비스에 연결된다.

 


228. Practice Test - Ingress -1 

1. We have deployed Ingress Controller, resources and applications. Explore the setup.

 

 

2. Which namespace is the Ingress Controller deployed in?

ingress-nginx

 

 

3. What is the name of the Ingress Controller Deployment?

ingress-nginx-controller

 

4. Which namespace are the applications deployed in?

app-space

 

5. How many applications are deployed in the app-space namespace?

Count the number of deployments in this namespace.

 

3개 

 

6. Which namespace is the Ingress Resource deployed in?

app space

 

7. what is the name of the ingress resource?

ingress-wear-watch

 

8. What is the Host configured on the Ingress Resource?

The host entry defines the domain name that users use to reach the application like www.google.com

 

all host

 

9. What backend is the /wear path on the Ingress configured with?

wear-service

 

10. At what path is the video streaming application made available on the Ingress?

/watch

 

11. If the requirement does not match any of the configured paths what service are the requests forwarded to?

no service

 

12. Now view the Ingress Service using the tab at the top of the terminal. Which page do you see?

404 error page

 

13. View the applications by appending /wear and /watch to the URL you opened in the previous step.

 

 

 

14. You are requested to change the URLs at which the applications are made available.

Make the video application available at /stream.

 

15. View the Video application using the /stream URL in your browser.

 

 

16. A user is trying to view the /eat URL on the Ingress Service. Which page would he see?

 

17. Due to increased demand, your business decides to take on a new venture. You acquired a food delivery company. Their applications have been migrated over to your cluster.

 

18. You are requested to add a new path to your ingress to make the food delivery application available to your customers.

Make the new application available at /eat.

 

19. View the Food delivery application using the /eat URL in your browser. 

 

20. A new payment service has been introduced. Since it is critical, the new application is deployed in its own namespace.

critical space

 

21. What is the name of the deployment of the new application?

webapp-pay

 

22. You are requested to make the new application available at /pay.

pay-service 가 있다 포트 8282 확인

ingress 만들기 

 

23. View the Payment application using the /pay URL in your browser.

 


231. Practice Test - Ingress - 2

1. We have deployed two applications. Explore the setup.

 

2. Let us now deploy an Ingress Controller. First, create a namespace called ingress-nginx.

We will isolate all ingress related objects into its own namespace.

 

3. The NGINX Ingress Controller requires a ConfigMap object. Create a ConfigMap object with name ingress-nginx-controller in the ingress-nginx namespace. 

 

 

4. The NGINX Ingress Controller requires two ServiceAccounts. Create both ServiceAccount with name ingress-nginx and ingress-nginx-admission in the ingress-nginx namespace.

 

 

 

5. We have created the Roles and RoleBindings for the ServiceAccount. Check it out!!

 

6. Let us now deploy the Ingress Controller. Create the Kubernetes objects using the given file. The Deployment and it's service configuration is given at /root/ingress-controller.yaml. There are several issues with it. Try to fix them.

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.1.2
    helm.sh/chart: ingress-nginx-4.0.18
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  minReadySeconds: 0
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app.kubernetes.io/component: controller
      app.kubernetes.io/instance: ingress-nginx
      app.kubernetes.io/name: ingress-nginx
  template:
    metadata:
      labels:
        app.kubernetes.io/component: controller
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/name: ingress-nginx
    spec:
      containers:
      - args:
        - /nginx-ingress-controller
        - --publish-service=$(POD_NAMESPACE)/ingress-nginx-controller
        - --election-id=ingress-controller-leader
        - --watch-ingress-without-class=true
        - --default-backend-service=app-space/default-http-backend
        - --controller-class=k8s.io/ingress-nginx
        - --ingress-class=nginx
        - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
        - --validating-webhook=:8443
        - --validating-webhook-certificate=/usr/local/certificates/cert
        - --validating-webhook-key=/usr/local/certificates/key
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: LD_PRELOAD
          value: /usr/local/lib/libmimalloc.so
        image: k8s.gcr.io/ingress-nginx/controller:v1.1.2@sha256:28b11ce69e57843de44e3db6413e98d09de0f6688e33d4bd384002a44f78405c
        imagePullPolicy: IfNotPresent
        lifecycle:
          preStop:
            exec:
              command:
              - /wait-shutdown
        livenessProbe:
          failureThreshold: 5
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1
        name: controller
        ports:
        - name: http
          containerPort: 80
          protocol: TCP
        - containerPort: 443
          name: https
          protocol: TCP
        - containerPort: 8443
          name: webhook
          protocol: TCP
        readinessProbe:
          failureThreshold: 3
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1
        resources:
          requests:
            cpu: 100m
            memory: 90Mi
        securityContext:
          allowPrivilegeEscalation: true
          capabilities:
            add:
            - NET_BIND_SERVICE
            drop:
            - ALL
          runAsUser: 101
        volumeMounts:
        - mountPath: /usr/local/certificates/
          name: webhook-cert
          readOnly: true
      dnsPolicy: ClusterFirst
      nodeSelector:
        kubernetes.io/os: linux
      serviceAccountName: ingress-nginx
      terminationGracePeriodSeconds: 300
      volumes:
      - name: webhook-cert
        secret:
          secretName: ingress-nginx-admission

---

apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.1.2
    helm.sh/chart: ingress-nginx-4.0.18
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
    nodePort: 30080
  selector:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
  type: NodePort

뭐가 문제인지 모르겠다. 그냥 복붙했다. 

 

 

7. Create the ingress resource to make the applications available at /wear and /watch on the Ingress service.

Also, make use of rewrite-target annotation field: -

nginx.ingress.kubernetes.io/rewrite-target: /


Ingress resource comes under the namespace scoped, so don't forget to create the ingress in the app-space namespace.

.

 

 

8. Access the application using the Ingress tab on top of your terminal.

 

 

확인


196. Networking - Section Introduction

이번 챕터는 배워야하는 선수 지식이 좀 많다.

 

 

198. Prerequisite - Switching Routing

네트워킹 파트를 공부하는데 있어 필요한 선수지식

Switcing, routing, dns, network namespace, docker networking 

 

Switching

두개의 호스트를 연결할려면 무엇이 필요할까? 

스위치에 연결해야한다. 스위치에 연결하기 위해선 각 호스트 인터페이스가 필요하다. 

ip link 명령어로 인터페이스를 확인할 수 있다.

eth0 라는 인터페이스를 사용한다.

스위치의 ip 주소가 192.168.1.0 이라고 가정하고 

ip addr add 로 호스트에 ip를 할당해보자

호스트 a 가 b로 ping 을 날리면 통신이 된다. 

Routing

비슷한 다른 네트워크 통신할려면 어떻해야할까?

192.168.1.11 에서 192.168.2.10 으로 통신할려면?

두 네트워크를 잇기 위해서 라우터를 사용한다. 

라우터도 마찬가지로 두 네트워크에 ip를 할당한다.

192.168.1.1과 192.168.2.1

b에서 c 로 패킷을 보내려고 할때 라우터의 위치는 어떻게 알까?

라우터는 네트워크에 있는 또 다른 디바이스로 인식된다. 어떻게 구분하는가

 

Gateway

 

게이트웨이가 있어야 외부 네트워크로 나갈 수 있다. 

 

호스트 b 에서 routes 명령을 해도 아무런 정보가 없다.

게이트웨이가 구성 안된 상태라서 외부에 접속 할 수 없다.

route 를 추가해줘야한다.  

2번 네트워크 스위치 ip 192.168.2.0 을   네트워크  1 라우터 ip 192.168.1.1 을 통해

(라우터를 등록하는 과정)

 

라우터가 등록되었다.

 

네트워크 2 에서 네트워크 1에 접속하고 싶으면 마찬가지로 라우터를 등록해야한다.

다른 네트워크로 가고 싶을때마다 라우터에 등록해야한다면 엄청나게 복잡할 것이다.

그대신

라우터가 인터넷 게이트웨이를 가졌다고 생각하고 default 라우터로 지정한다. 

default 대신에 0.0.0.0 로 표기해도 된다.

모든 네트워크를 의미

만약 네트워크 2에서 네트워크1 로 가는 라우터, 외부 인터넷 접속을 하는 라우터를 분리하고 싶다면

 

192.168.1.0 으로 가능 라우터 하나

0.0.0.0 외부로 가능 라우터 하나 

두개를 등록한다.

a,b,c 호스트가 있고 

a,b 같은 스위치 b,c 같은 스위치에 있다.

스위치로부터 ip를 부여받고 

b는 두개의 ip를 배정받는다. 

a가 c 와 통신하고 싶다면 어떻해야하는가?

 

호스트a 192.168.1.5 에서 ping 을 날려보자 

192.168.2.5 로 보내면 접속불가이다.

라우터가 없기 때문에 어떻게 가는지 모른다. 

먼저 호스트 a에서 route를 추가한다.

 192.168.2.0 스위치로 가는 라우터는 192.168.1.6 

a에서 c로 패킷을 보내고 c 가 응답을 하기 위해 

마찬가지로 192.168.1.0 네트워크로 가기 위해 192.168.2.6 네트워크에 연결한다. 

이제 호스트 a에서 ping은 보내지지만 응답이 없다? 

 

By default, in Linux, packets are not forwarded from one interface to the next.

 

다른 인터페이스끼리 한번에 패킷이 전달 되지 않는다고 한다. ( 리눅스 보안 때문?)

호스트 b 는 eth0, eth1 두개의 인터페이스를 가지고 있다. 

cat /proc/sys/net/ipv4/ip_forward 를 실행하면 0 의 값을 가진다.

해당 값을 1로 바꾼다. 

이제 다른 인터페이스라도 패킷 전달이 가능해진다.

ping 응답 가능

리부트하면 초기화 되기 때문에 /etc/sysctl.conf 로 가서 값을 변경하면 값이 유지된다.

 

명령어 정리

 

ip link - 인터페이스 확인

ip addr add - ip 할당하기

ip route - 라우터 확인하기

ip route add - 라우터 추가하기

cat /proc/sys/net/ipv4/ip_forward - 다른 인터페이스끼리 패킷 전달 허용 

 


199. Prerequisite - DNS

호스트 a와 호스트 b 가 있다. 

a에서 ping 날리면 응답이 오지만 호스트 네임 db 로 지정하고 보내면 모른다.

etc/hosts 파일에 192.168.1.11 은 db 라고 등록하고 ping db를 날리면 응답이 온다.

문제는 여기서 정한 이름이 호스트 a에서만 정해진 약속이라는 점

b의 호스트 네임을 변경해도 여전히 db 에 접속하능하고 

google.com 이름으로 정해도 핑이 보내진다.

 

Name Resolution

이름을 함부로 정한 것을 name Resolution 이라고 한다. 

호스트 c 가 추가된다면 etc/hosts 파일을 세번 수정해야한다. 

호스트가 많이 추가되면 지옥이다.

하나의 ip가 변경되면 변경을 수도 없이 해야한다.

모든 호스트의 etc/hosts 를 수정하는 것이 아닌 해당 역할을 중앙에서 처리하는 하나의 서버에 위임한다.

DNS

이제 모든 호스트이 dns 서버에 접속한다!

대신 모든 호스트의 /etc/resolv.cof 파일에 nameserver 정보가 담긴다.

pind db로 핑을 날릴 수도 있다. 

 

이제 /etc/hosts 파일을 일일히 수정할 필요없다. 

test 용 서버를 두고 싶을때 하나의 호스트의 etc/hosts 파일만 수정하고 해당 호스트에서만 접속하게 한다. 

이런 용도도 있다.

 

이름이 중첩됬을때는?

호스트 a 에 192.168.1.115 를 test로 

dns 서버에 192.168.1.116 이 test로 

같은 이름인 경우에는...

먼저 local  을 선택하고 접속이 불가하면 dns의 경로로 간다. 

우선 순위를 바꾸고 싶다면

/etc/nsswithc.conf 를 수정한다.

files 는 로컬 dns

순서를 바꾸면 dns 먼저 탐색하게 할 수 있다. 

etc/hosts, nameserver 둘 다 없는 도메인을 입력하면 접속 실패가 뜬다. 

.8nameserver 에 구글이 운영하는 공용 네임서버 8.8.8.8 에 등록하거나 

dns 서버에 forward all t0 8.8.8.8 을 입력하여 외부로 보낼 수 있다.

이제 외부로 갈 수 있다.

Domain Names

top level domain

맨 뒤에 오는 거 

 

google 앞에 오는 www, drive , email 이런 건 서브 도메인이라고 한다.

apps.google.com 을 접속한다고 가정하면

먼저 local dns는 google이 뭔지도 모른다. 

. root DNS 로 접근한다. 

.com 등의 탑 레벨 도메인으로 간후 

google dns 로 간다. 

google dns 에서 apps 가 누군지 확인하면 216.58.221.78 의 ip 주소가 나온다. 

해당 주소를 로컬 캐시에 저장하고  다음번 접속시 저장된 ip를 사용하여 빠르게 접속한다. 

 

 Record Types

 

nslookup

 

nslookup은 로컬 etcd/hosts 파일을 확인하지 않는다. dns서버만 쿼리한다. 

ping 대신 lookup, dig 으로 통신 상태 확인 가능하다. 

 

 

dig


201. Prerequisite - Network Namespaces

 

리눅스 네트워크 네임스페이스에 대해 배워볼거다. 

집을 방으로 분리하듯이 호스트는 네임스페이스를 이용하여 격리시킨다.

컨테이너를 네임스페이스로 감싼다.

컨테이너 안에서 ps aux 

호스트에서 ps aux 에서

프로세스 root 를 똑같이 감시할 수 있으나 다른 프로세스 id를 갖는다. 

(호스트 관리자는 네임스페이스안의 프로세스도 볼 수 있다.)

 

Network Namespace

호스트가 lan 과 연결될때 routing 테이블 과 arp 테이블을 갖는다.

네임스페이스 안에 컨테이너를 생성

컨테이너를 라우팅 테이블에 대한 정보를 어떻게 알고 통신할까?

컨테이너도 가상 인터페이스와 라우팅, arp 테이블을 갖는다!

Create Network NS

in netns add  명령어로 netns 를 추가한다.

Exec in network ns

ip link 로 인터페이스를 확인 할 수 있다. 

netns 로 들어가서 인터페이스를 확인 할려면?

ip netns exec red ip link

ip -n red link

 

exec 으로 접속해서 확인하거나 -n 옵션으로 확인하거나

호스트에서는 인터페이스 두개 다 확인가능하고 

netns 로 들어가서 확인하면 한개만 확인가능하다.

 

arp 테이블을 확인할때도 마찬가지 

호스트에서는 다 확인가능하지만

netns 에선 해당 arp 만 확인가능

라우팅 테이블도 똑같다. 

 

두개의 netns 링크

다른 두개의 netns 인터페이스를 연결하고 싶다면 ? 

먼저 호스트에서 가상 인터페이스를 두개 만든다. 

ip link add veth-red type veth peer name veth-blue

veth 하나를 netns 로 옮긴다.

ip link set veth-red netns red

나머지 veth를 netns로 옮긴다.

ip link set veth-red netns blue

네임스페이스 인터페이스에 ip를 부여한다.

ip -n red addr add 192.168.15.1 dev veth-red

마지막으로 link set up 명령을 통해 인터페이스를 사용 가능하게 만든다 .

ip -n red link set veth-red

핑을 날리거나 arp 테이블을 확인할 수 있다.

호스트에서 arp 를 날리면 netns 의 arp, 인터페이스를 확인할 수 없다.

 

netns 가 여러개라면?

netns 가 여러개라면 위의 작업을 수동으로 하기 힘들 것이다.

대신 가상 스위치를 구성하는 것이 효율적이다. 

Virtual Switch 만들기

리눅스 브릿지, 오픈 스위치 등을 사용할 수 있다.

 

Linux Bridge

호스트에서 bridge 타입 가상 인터페이스를 만든다. 

ip link add v-net-0 type bridge

호스트에서 ip link 하면 인터페이스로 확인 가능하다. 

down 상태 

 

ip link set dev v-net-0 up 으로 인터페이스를 켠다. 

 

스위치에 모두 연결하기 전에 이전에 만든 link를 없애준다. 

ip -n red link del veth-red

인터페이스를 가상의 인터페이스와 링크한다.

ip link add veth-red type veth peer name veth-red-br

veth-red-br 은 이름만 존재

인터페이스를 netns 로 이동시키고

ip link set veth-red netns red

나머지 가상의 인터페이스를 가상 스위치에 설치한다.

ip link set veth-red-br master v-net-0

블루도 마찬가지

인터페이스에 ip를 부여한다.

ip -n red addr add 192.168.15.1 dev veth-red

마지막으로 인터페이스를 켠다

ip -n red link set veth-red up

 

4개의 host 다 연결되었다고 가정

호스트에서 netns red 의 ip 192.168.15.1 로 ping 때리면 안간다.

같은 네임스페이스가 아니기 때문

호스트에서 가상 스위치에 ip를 부여한다.

ip addr add 192.168.15.5/24 dev v-net-0

 

기존에 다른 netsns 에 ip를 부여했기 때문에 5번이 아닐까 싶네

스위치도 하나의 디바이스로 인식하기 때문에 ip를 가진다.

이제 호스트에서 red netns 로 ping 이 보내진다. 

가상 스위치로 라우팅 되서 가능한 것 같다.

해당 네트워크는 네임스페이스 안에 있기 때문에 외부로 접근할 수 없다.

외부로 나갈려면 호스트의 포트를 통해서 나가야한다.

외부의 192.168.1.3 으로 접속할려면 어떻게 해야 하는가

블루 netns 에서 192.168.1.3 에 접속해보자 

ip netns exec blue pin 192.168.1.3

라우트 명령으로 라우팅 확인해보자

ip netns exec blue route

가상 스위치로 가는 라우터만 가지고 있다.

네트워크 접속 불가라고 뜬다.

 

어떻게해야할까

가상 스위치에 연결된 가상 인터페이스가 호스트에 있는 또 다른 인터페이스라고 생각하면 된다. 

블루 netns 에서 192.168.1.3 으로 가능 라우터를 추가할려면 

ip netns exec blue ip route add 192.168.1.0/24 via 192.168.15.5 

라우터를 추가한다. 

스위치 192.168.1.0 으로 가는데 있어 가상 스위치 인터페이스의 ip는 게이트웨이가 되어준다. 

이제 블루 netns 에서 192.168.1.3 으로 ping 을 날리면 가지만 응답이 없다. 

(리눅스에선 다른 인터페이스끼리 한번에 패킷 전달이 안된다. ... 인 줄 알았으나...)

 

블루 netns 에선 192.168.1.3 까지 라우팅 경로를 알고 있으나 

192.168.1.3 입장에서는 어느 경로로 응답해야하는지 정보가 없다.

 

호스트에 

iptables -t nat -A POSTROUTING -s 192.168.15.0/24 -j MASQUERADE 

를 추가한다.

해당 패킷을 받으면 호스트로부터 받은 패킷이라고 생각한다.(netns 로부터 온것이 아닌)

이제 응답을 받을 수 있다.

스위치가 인터넷과 연결되어있고

블루 netns 에서 8.8.8.8 로 접속할려고 하면 실패한다.

라우터 등록이 안되어있기 때문에

 

default 게이트웨이를 설정함으로써 해결할 수 있다.

외부 인터넷으로부터 응답을 받을 수 있다.

호스트에서 블루netns 로 핑을 보내면 가지만 외부 호스트 192.168.1.3 에서 보내면 접근 불가이다.

호스트에서 포트 포워딩 하는 방법이 있다.

ip tables -t nat -A PREROUTING --dport 80 --to-destination 192.168.15.2:80 -j DNAT 

 


167. Image Security

Image

예시 여기 이미지 nginx 는 어디서 왔을까?
.
docker 레지스트리 library 에서 가져온다.

Private Repository

private 레포지토리에서 가져올 수 있다.

먼저 private-registry.io 에 로그인 해야한다. 

image 에 전체 경로를 써야한다.

쿠버네티스가 어떻게 private 레포지토리에 인증할 수 있을까? 

워커노드의 도커 런타임에 어떻게 인증을 전달할 수 있을까 ?

-> secret 을 이용한다.

파드 정의에 secret이 들어간다.


168. Practice Test - Image Security 

1. What secret type must we choose for docker registry?

docker-registry 를 사용한다. 

 

 

2. We have an application running on our cluster. Let us explore it first. What image is the application using?

nginx 알파인

 

3.  We decided to use a modified version of the application from an internal private registry. Update the image of the deployment to use a new image from myprivateregistry.com:5000

The registry is located at myprivateregistry.com:5000. Don't worry about the credentials for now. We will configure them in the upcoming steps.

image 앞에 경로를 추가

4. Are the new PODs created with the new images successfully running?

작동 안된다 credential 문제인듯 

 

5.

Create a secret object with the credentials required to access the registry.

Name: private-reg-cred
Username: dock_user
Password: dock_password
Server: myprivateregistry.com:5000
Email: dock_user@myprivateregistry.com

 

 

 

6. Configure the deployment to use credentials from the new secret to pull images from the private registry

 

deployment 에 secret 을 쓸 수 있게 하자 .

 

Pull an Image from a Private Registry | Kubernetes

 

Pull an Image from a Private Registry

This page shows how to create a Pod that uses a Secret to pull an image from a private container image registry or repository. There are many private registries in use. This task uses Docker Hub as an example registry. 🛇 This item links to a third party

kubernetes.io

 

image 밑에 imagePullsecrets 로 넣자 .

 

7. Check the status of PODs. Wait for them to be running. You have now successfully configured a Deployment to pull images from the private registry.

잘돌아간다. 

 


170. Pre-requisite - Security in Docker

컨테니어와 호스트는 같은 커널을 공유한다. 

컨테이너의 네임스페이스는 밖으로 못나가지만 호스트 단의 네임스페이스는 컨테이너도 다 볼 수 있다. 

 

컨테이너 안에서 ps 명령어로 확인하면 하나의 프로세스만 뜨지만. 

 

호스트 단에 ps 명령어로 확인하면 다 나온다.

여기서는 root 의 pid 가 다르게 나올뿐 (컨테이너에서는 pid 1 이었다.)

마찬가지로 호스트 단의 root  유저와 컨테이너의 root 유저는 다르다 .

root 유저의 권한 어마무시해

권한을 주고 싶다면 --cap-add 명령을 하면 된다 .

또는 cap-drop 으로 권한을 제거할 수 있다. 

privileged 로 모두 가능하게 할 수 있다. 

 


171. Security contexts

도커에 유저를 추가하거나 커널 기능을 주거나.

쿠버네티스도 마찬가지

 

파드레벨
컨테이너 레벨

runAsUser 또는 capabity  등 이용가능


172. Practice Test - Security Contexts

1. What is the user used to execute the sleep process within the ubuntu-sleeper pod?

In the current(default) namespace.

파드에 접속한 후 whoami

 

 

2.

Edit the pod ubuntu-sleeper to run the sleep process with user ID 1010.

Note: Only make the necessary changes. Do not modify the name or image of the pod.

 

 

3. A Pod definition file named multi-pod.yaml is given. With what user are the processes in the web container started?

The pod is created with multiple containers and security contexts defined at the Pod and Container level.

오류 인가 안뜬다??

 

1002

 

4. With what user are the processes in the sidecar container started?

The pod is created with multiple containers and security contexts defined at the Pod and Container level.

명시 안되었으니 파드 단위 1001 

 

5.

Update pod ubuntu-sleeper to run as Root user and with the SYS_TIME capability.

Note: Only make the necessary changes. Do not modify the name of the pod.

apiVersion: v1
kind: Pod
metadata:
  name: ubuntu-sleeper
  namespace: default
spec:
  containers:
  - command:
    - sleep
    - "4800"
    image: ubuntu
    name: ubuntu-sleeper
    securityContext:
      capabilities:
        add: ["SYS_TIME"]

securityContext 를 추가한다. 

 

 

6.

Now update the pod to also make use of the NET_ADMIN capability.

Note: Only make the necessary changes. Do not modify the name of the pod.

apiVersion: v1
kind: Pod
metadata:
  name: ubuntu-sleeper
  namespace: default
spec:
  containers:
  - command:
    - sleep
    - "4800"
    image: ubuntu
    name: ubuntu-sleeper
    securityContext:
      capabilities:
        add: ["SYS_TIME", "NET_ADMIN"]

net_admin 추가

 

파드 실행 중이니까 바로 수정안된다. 

파드 제거하고 수정된 경로에서 kubectl apply -f [파일명]

 


174. Network Policy

Traffic

웹서버, 백엔드 서버, db 서버 이렇게 있다.

Ingress & Egress

Ingress - 들어오는 거

Egress - 나가는 거

Network Security

노드와 파드들은 각자 ip 를 가지고 있다. 

파드들은 서로 통신 가능해야한다.

쿠버네티스는 기본적으로 파드들끼리 allow 정책을 한다. 

쿠버네티스를 예시로 들어보자. 모두 파드로 치환됨.

파드니까 모두 서로 통신 가능하다. 

네트워크 정책을 적용해서 트래픽을 통제하자

레이블을 지정한 후 적용한다.

Network Policy - Rules 

ingress 정책 

특정 포트, 파드로 통신마 허용함

Network Policy - yaml 구성

파드 셀렉터 먼저 오고 정책 타입이 들어간다. 

인그레스 관련해서 모두 영향 받음

당연히 create 명령
네트워크 정책에 영향 받는 것과 아닌 것 확인


175. Developing Network Policy

 

예로 들어보자

web 으로부터 db 접근을 막아야한다. 

db와 api 먼저 확인하자
db 입장에서 api 로부터 들어오는 ingress 만 잘관리하면 된다.

요청 받은 후 응답을 자동으로 해야하기 때문에 egress는 필요없다. 

yaml 파일 예시
네임스페이스가 필요한 경우 name 밑에 기입하자

 

특정 ns가 필요하면 matchLabels 밑에 명시

이 상황에서 podSelector 가 없다면 ?

Staging에서 들어오는 모든 트래픽이 허용된다. 

다시 api pod 로 변경

외부 백업 서버와 연결하고 싶다면 ?

ipBlock 을 추가한다. 

from 아래에선 독립적으로 조건이 적용된다.

Egress 추가하기 


176. Practice Test - Network Policy

1. How many network policies do you see in the environment?

 

We have deployed few web applications, services and network policies. Inspect the environment.

1개

 

2. What is the name of the Network Policy?

payroll-policy

 

3. Which pod is the Network Policy applied on?

payroll

 

 

4. What type of traffic is this Network Policy configured to handle?

 

ingress 만 

 

5.  What is the impact of the rule configured on this Network Policy?

internal 

 

6. What is the impact of the rule configured on this Network Policy?

internal pod can access port 8080 on payroll pod

 

7. Access the UI of these applications using the link given above the terminal.

 

8. Perform a connectivity test using the User Interface in these Applications to access the payroll-service at port 8080.

9. Perform a connectivity test using the User Interface of the Internal Application to access the external-service at port 8080.

 

10.

Create a network policy to allow traffic from the Internal application only to the payroll-service and db-service.

Use the spec given below. You might want to enable ingress traffic to the pod to test your rules in the UI.

Policy Name: internal-policy
Policy Type: Egress
Egress Allow: payroll
Payroll Port: 8080
Egress Allow: mysql
MySQL Port: 3306
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: internal-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      name: internal
  policyTypes:
  - Egress
  - Ingress
  ingress:
    - {}
  egress:
  - to:
    - podSelector:
        matchLabels:
          name: mysql
    ports:
    - protocol: TCP
      port: 3306

  - to:
    - podSelector:
        matchLabels:
          name: payroll
    ports:
    - protocol: TCP
      port: 8080

  - ports:
    - port: 53
      protocol: UDP
    - port: 53
      protocol: TCP

 


휴 드디어 그 많은 분량의  section7 security 가 끝났다.

cka 너무 멀고 먼 길이여

화이팅

 

 


150. Certificates API 

사용자와 클러스터가 있는 상황이다. 

나는 인증서와 키를 가지고 있다. 

사용자를 추가해야한다면? 

 

b 사용자의 인증서를 관리자한테 주고 관리자가 클러스터에 넘겨 서명을 받는다. 

그리고 사용한다. 

 

쿠버네티스  CA 서버

인증서, 키파일은 서버에 안전하게 저장된다.

마스터 노드에 ca 서버가 있다면 마스터 노드 또한 ca 서버이다 ? 

 

매번 인증서를 넘기고 서명 받는 작업을 하는 것은 귀찮다. 

 

Certificates API 가 하는일

 

인증서를 건낸후 바로 서명 받고 돌려받는 것이 아니라 CSR객체를 만든다 .

객체가 생성되면 모든 유저들이 요청을 검토하고 확인할 수 있다.

1. openssl genrsa - 키생성

2. openssl req - 관리자에게 요청

3. 관리자는 서명 요청 객체 생성

요청은 베이스 64 명령어로 암호화 해야한다.

그 후 인코딩된 텍스트를 요청 필드로 옮기고 요청을 제출한다.

 CSR 이 생성된다. 

csr 확인하기 

인증서 서명하기 

csr yaml 파일을 확인하면 cert 부분은 base 64 로 암호화되어있다. 

 

ca는 controlplane 어느부분에서 담당할까 ?

 

컨트롤러 매니저에서 담당한다. 

controller manager 안에 csr-approving, csr-sigining 이 존재한다.

 

누구든 인증서에 서명하려면 CA 서버의 root 인증서와 개인키 


151. Practice Test - Certificates API 

1.

A new member akshay joined our team. He requires access to our cluster. The Certificate Signing Request is at the /root location.

 

Inspect it

csr과 key 가 있다. 

 

2.

Create a CertificateSigningRequest object with the name akshay with the contents of the akshay.csr file

As of kubernetes 1.19, the API to use for CSR is certificates.k8s.io/v1.

Please note that an additional field called signerName should also be added when creating CSR. For client authentication to the API server we will use the built-in signer kubernetes.io/kube-apiserver-client.

Certificate Signing Requests | Kubernetes

 

Certificate Signing Requests

FEATURE STATE: Kubernetes v1.19 [stable] The Certificates API enables automation of X.509 credential provisioning by providing a programmatic interface for clients of the Kubernetes API to request and obtain X.509 certificates from a Certificate Authority

kubernetes.io

Create CertificateSigningRequest

Create a CertificateSigningRequest and submit it to a Kubernetes Cluster via kubectl. Below is a script to generate the CertificateSigningRequest.

cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: myuser
spec:
  request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ1ZqQ0NBVDRDQVFBd0VURVBNQTBHQTFVRUF3d0dZVzVuWld4aE1JSUJJakFOQmdrcWhraUc5dzBCQVFFRgpBQU9DQVE4QU1JSUJDZ0tDQVFFQTByczhJTHRHdTYxakx2dHhWTTJSVlRWMDNHWlJTWWw0dWluVWo4RElaWjBOCnR2MUZtRVFSd3VoaUZsOFEzcWl0Qm0wMUFSMkNJVXBGd2ZzSjZ4MXF3ckJzVkhZbGlBNVhwRVpZM3ExcGswSDQKM3Z3aGJlK1o2MVNrVHF5SVBYUUwrTWM5T1Nsbm0xb0R2N0NtSkZNMUlMRVI3QTVGZnZKOEdFRjJ6dHBoaUlFMwpub1dtdHNZb3JuT2wzc2lHQ2ZGZzR4Zmd4eW8ybmlneFNVekl1bXNnVm9PM2ttT0x1RVF6cXpkakJ3TFJXbWlECklmMXBMWnoyalVnald4UkhCM1gyWnVVV1d1T09PZnpXM01LaE8ybHEvZi9DdS8wYk83c0x0MCt3U2ZMSU91TFcKcW90blZtRmxMMytqTy82WDNDKzBERHk5aUtwbXJjVDBnWGZLemE1dHJRSURBUUFCb0FBd0RRWUpLb1pJaHZjTgpBUUVMQlFBRGdnRUJBR05WdmVIOGR4ZzNvK21VeVRkbmFjVmQ1N24zSkExdnZEU1JWREkyQTZ1eXN3ZFp1L1BVCkkwZXpZWFV0RVNnSk1IRmQycVVNMjNuNVJsSXJ3R0xuUXFISUh5VStWWHhsdnZsRnpNOVpEWllSTmU3QlJvYXgKQVlEdUI5STZXT3FYbkFvczFqRmxNUG5NbFpqdU5kSGxpT1BjTU1oNndLaTZzZFhpVStHYTJ2RUVLY01jSVUyRgpvU2djUWdMYTk0aEpacGk3ZnNMdm1OQUxoT045UHdNMGM1dVJVejV4T0dGMUtCbWRSeEgvbUNOS2JKYjFRQm1HCkkwYitEUEdaTktXTU0xMzhIQXdoV0tkNjVoVHdYOWl4V3ZHMkh4TG1WQzg0L1BHT0tWQW9FNkpsYWFHdTlQVmkKdjlOSjVaZlZrcXdCd0hKbzZXdk9xVlA3SVFjZmg3d0drWm89Ci0tLS0tRU5EIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLQo=
  signerName: kubernetes.io/kube-apiserver-client
  expirationSeconds: 86400  # one day
  usages:
  - client auth
EOF

 

복붙한다.

 

csr 파일의 형식과 다르다. 

 

csr 파일을 -> base 64 로 암호화한뒤 akshay.yaml 파일의 req 부분에 복붙한다. 

-w 0 옵션으로 한줄 출력

실행하기

 

3. What is the Condition of the newly created Certificate Signing Request object?

pending

 

4. Approve the CSR Request

요청 승인하기 

 

5. How many CSR requests are available on the cluster?

2개

 

6.

During a routine check you realized that there is a new CSR request in place. What is the name of this request?

 

agent smith

 

7.

Hmmm.. You are not aware of a request coming in. What groups is this CSR requesting access to?

Check the details about the request. Preferebly in YAML.

열어서 확인해보자

masters 그룹에서 요청

 

8. That doesn't look very right. Reject that request.

 

k certificate deny agent-smith 로 요청 거부할 수 있다. 

 

9. Let's get rid of it. Delete the new CSR object


153. KubeConfig

사용자가 my-kube-playground   클러스터로 인증서 요청을 날린다면 

 

아래는 kubectl 을 이용한 요청 

키, 인증서, ca

매번하면 귀찮기 때문에 kubeconfig 를 만들어서 쉽게 사용

kubeconfig file 의 경로는 $HOME/.kube/config 이다. 

기본으로 설정되어있기 때문에 이때까지 생략하고 잘 쓴거

 KubeConfigFile의 구성

Clusters, Contexts, Users 

이 세가지 context는 어떤 유저가 어떤 클러스터에 접근할 수 있는지 명시한다. 

config 파일이 위와 같다면

mykubeplayground, certificate-authority 는 클러스터로 간다. 

키, 인증서는 users 로 간다. 

두개를 조합해서 컨텍스트를 만든다. 

 

yaml 파일에서 확인 

clusters, user, context 이렇게 되어있다. 

 

파일은 그대로 두고 kubectl 로 실행 

 

kubectl 은 어떤 컨텍스트를 골라야할까 ? 

currentcontext를 사용해 기본 컨텍스트 정의 

 

kubectl config

클러스터 확인 가능

 

현재 컨텍스트 변경하기 

use context 로 컨텍스트를 변경한다. 

 

네임스페이스 관련

네임스페이스는 클러스터 단위에서 생성된다.

컨텍스트 부분에 네임스페이스도 명시한다. 

Certificates in kubeConfig

인증서 파일의 경우 전체 경로를 쓰는 것이 좋다.

ca 파일의 경우 그냥 crt 내용을 암호화해서 복붙할 수도 있다. 


154. Practice Test - KubeConfig

1.  Where is the default kubeconfig file located in the current environment? 

Find the current home directory by looking at the HOME environment variable.

실행해보고 확인가능 

/root/.kube/config

 

2. How many clusters are defined in the default kubeconfig file?

 

1개

 

3. How many Users are defined in the default kubeconfig file?

1개

 

4. How many contexts are defined in the default kubeconfig file?

1개

 

5. What is the user configured in the current context?

6. What is the name of the cluster configured in the default kubeconfig file?

kubernetes

 

7. A new kubeconfig file named my-kube-config is created. It is placed in the /root directory. How many clusters are defined in that kubeconfig file?

 

4개

 

8. How many contexts are configured in the my-kube-config file?

4개

 

9. What user is configured in the research context?

 

dev-user

 

10. What is the name of the client-certificate file configured for the aws-user?

 

aws-user.crt

 

11. What is the current context set to in the my-kube-config file?

 

12.

I would like to use the dev-user to access test-cluster-1. Set the current context to the right one so I can do that.

Once the right context is identified, use the kubectl config use-context command.

 

my-kubeconfig 가 기본 config 파일이 아니기 때문에 --kubeconfig 옵션이 필요하다. 

 

13. We don't want to have to specify the kubeconfig file option on each command. Make the my-kube-config file the default kubeconfig.

 

파일을 기본 디렉터리로 옮긴다. 

 

14.

With the current-context set to research, we are trying to access the cluster. However something seems to be wrong. Identify and fix the issue.

Try running the kubectl get pods command and look for the error. All users certificates are stored at /etc/kubernetes/pki/users.

 

 

developer.crt. 가 아니라 dev-user.crt 로 되어있다. 

/root/.kube/config 파일을 수정하자. 

 


157. API Groups

api 버전을 확인하고 싶다면? 

master 노드 포트에 접속해서 확인가능하다. 

이렇게도 접속가능하다. 

 

api 포드에 대해 집중해보자 

쿠버네티스api 는 여러종류로 나눠진다. 

core, named api 그룹에 대해 알아보자

core api 에는 우리가 아는 중요한거 다 들어있다. 

naemd api 에는 다양한 기능들이 있다. 

 

마스터 노드 포트로 바로 접속하면 사용 가능한 api 그룹 리스트가 나온다. 

모든 리소스 출력하기

 

인증서 없이 클러스터 api 에 접속할 수 없다. 

키,인증서, ca 를 넘겨야한다. 

Kubectl Proxy 로 접속하기

프록시로 접속한후 8001 포트를 통해 api 리스트를 가져올 수 있다. ( 인증서 필요 없음) 

Kube proxy ≠ kubectl proxy

엄연히 다른거다. 

 

+ Recent posts