kubeadm으로 일반적인 쿠버네티스 설치를 진행할 경우, 오드로이드에서는 성능을 감당하기가 쉽지 않다. CPU가 터질 것 같다는 느낌이 드는데 그래서 다른 대안을 찾아보다가, k3s라는 것을 설치해 보기로 했다.

k3s 실행 파일은 뒤의 파라미터에 따라 server혹은 agent로 동작하는데, server의 경우 쿠버네티스 마스터, agent는 슬레이브가 된다.

k3s server

서버의 가능한 옵션은 여러 가지가 있는데 이 곳에서 확인할 수 있다. 설치를 위해 우선 이 정도로 정리해 보기로 했다.

  • cluster-cidr: 리소스 Pod이 사용할 ip의 대역을 지정한다.
  • service-cidr: 리소스 services가 사용할 ip의 대역을 지정한다.
  • cluster-dns: coredns가 동작할 IP를 지정한다. service-cidr을 변경할 것이므로, 같이 변경해 주려 한다.
  • no-deploy: k3s 설치시 함께 설치되는 것들을 선택하여 제외할 수 있다. servicelb나 metrics-server는 제외하려 한다.
  • cluster-init: master 노드의 클러스터링을 위해 이 옵션으로 실행한다.
  • token: 마스터 혹은 슬레이브에서 클러스터링을 위해 사용할 토큰을 지정한다.
$ curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server --cluster-cidr \"172.20.0.0/14\" --service-cidr \"172.24.0.0/14\" --cluster-dns \"172.24.0.10\" --no-deploy \"servicelb\" --no-deploy \"metrics-server\" --no-deploy \"local-storage\"" sh -
[INFO]  Finding latest release
[INFO]  Using v1.0.0 as release
[INFO]  Downloading hash https://github.com/rancher/k3s/releases/download/v1.0.0/sha256sum-arm.txt
[INFO]  Downloading binary https://github.com/rancher/k3s/releases/download/v1.0.0/k3s-armhf
[INFO]  Verifying binary download
[INFO]  Installing k3s to /usr/local/bin/k3s
[INFO]  Creating /usr/local/bin/kubectl symlink to k3s
[INFO]  Creating /usr/local/bin/crictl symlink to k3s
[INFO]  Creating /usr/local/bin/ctr symlink to k3s
[INFO]  Creating killall script /usr/local/bin/k3s-killall.sh
[INFO]  Creating uninstall script /usr/local/bin/k3s-uninstall.sh
[INFO]  env: Creating environment file /etc/systemd/system/k3s.service.env
[INFO]  systemd: Creating service file /etc/systemd/system/k3s.service
[INFO]  systemd: Enabling k3s unit
Created symlink /etc/systemd/system/multi-user.target.wants/k3s.service → /etc/systemd/system/k3s.service.
[INFO]  systemd: Starting k3s

$ kubectl cluster-info
Kubernetes master is running at https://127.0.0.1:6443
CoreDNS is running at https://127.0.0.1:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

$ kubectl get node
NAME                       STATUS   ROLES    AGE     VERSION
odroidu3-00001   Ready    master   3m35s   v1.16.3-k3s.2


$ cat /var/lib/rancher/k3s/server/node-token
K10...

k3s agent

클라이언트의 설치는 다음과 같다.

$ curl -sfL https://get.k3s.io | K3S_URL="https://192.168.129.224:6443" K3S_TOKEN="K10..." sh -
[INFO]  Finding latest release
[INFO]  Using v1.0.0 as release
[INFO]  Downloading hash https://github.com/rancher/k3s/releases/download/v1.0.0/sha256sum-arm.txt
[INFO]  Downloading binary https://github.com/rancher/k3s/releases/download/v1.0.0/k3s-armhf
[INFO]  Verifying binary download
[INFO]  Installing k3s to /usr/local/bin/k3s
[INFO]  Creating /usr/local/bin/kubectl symlink to k3s
[INFO]  Skipping /usr/local/bin/crictl symlink to k3s, command exists in PATH at /usr/bin/crictl
[INFO]  Skipping /usr/local/bin/ctr symlink to k3s, command exists in PATH at /usr/bin/ctr
[INFO]  Creating killall script /usr/local/bin/k3s-killall.sh
[INFO]  Creating uninstall script /usr/local/bin/k3s-agent-uninstall.sh
[INFO]  env: Creating environment file /etc/systemd/system/k3s-agent.service.env
[INFO]  systemd: Creating service file /etc/systemd/system/k3s-agent.service
[INFO]  systemd: Enabling k3s-agent unit
Created symlink /etc/systemd/system/multi-user.target.wants/k3s-agent.service → /etc/systemd/system/k3s-agent.service.
[INFO]  systemd: Starting k3s-agent

설치 완료 후 노드 정보는 다음과 같다.

$ kubectl get node
NAME                       STATUS   ROLES    AGE     VERSION
odroidu3-00004   Ready    <none>   43s     v1.16.3-k3s.2
odroidu3-00006   Ready    <none>   39s     v1.16.3-k3s.2
odroidu3-00001   Ready    master   4m35s   v1.16.3-k3s.2
odroidu3-00007   Ready    <none>   30s     v1.16.3-k3s.2
odroidu3-00005   Ready    <none>   17s     v1.16.3-k3s.2

kubectl 설정

kubeconfig의 정보는 k3s 기본 경로가 /etc/rancher/k3s/k3s.yam가 된다.

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS0...
    server: https://127.0.0.1:6443
  name: default
contexts:
- context:
    cluster: default
    user: default
  name: default
current-context: default
kind: Config
preferences: {}
users:
- name: default
  user:
    password: a90...
    username: admin

우선 이 파일을 챙겨서 kubectl을 실행할 때 사용해 보자. 다른 PC의 ~/.kube/config에 저장하였다.

$ kubectl get pod --all-namespaces
NAMESPACE     NAME                                READY   STATUS    RESTARTS   AGE
kube-system   coredns-d798c9dd-7gddk              1/1     Running   0          10m

음 잘 된다.

MetalLB

아까 설치할 때 servicelb를 제외했는데(k3s의 klipper-lb) 여기서는 MetalLB를 설치해서 사용해 보자. 설치는 여기 가이드의 manifest를 그대로 사용하였다.

$ kubectl apply -f https://raw.githubusercontent.com/google/metallb/v0.8.3/manifests/metallb.yaml
namespace/metallb-system created
podsecuritypolicy.policy/speaker created
serviceaccount/controller created
serviceaccount/speaker created
clusterrole.rbac.authorization.k8s.io/metallb-system:controller created
clusterrole.rbac.authorization.k8s.io/metallb-system:speaker created
role.rbac.authorization.k8s.io/config-watcher created
clusterrolebinding.rbac.authorization.k8s.io/metallb-system:controller created
clusterrolebinding.rbac.authorization.k8s.io/metallb-system:speaker created
rolebinding.rbac.authorization.k8s.io/config-watcher created
daemonset.apps/speaker created
deployment.apps/controller created

그러면,

$ kubectl get svc --all-namespaces
NAMESPACE     NAME         TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)                                     AGE
default       kubernetes   ClusterIP      172.24.0.1       <none>        443/TCP                                     70m
kube-system   kube-dns     ClusterIP      172.24.0.10      <none>        53/UDP,53/TCP,9153/TCP                      70m
kube-system   traefik      LoadBalancer   172.27.120.161   <pending>     80:32008/TCP,443:30444/TCP,8080:30726/TCP   68m
$ kubectl get pod --all-namespaces
NAMESPACE        NAME                          READY   STATUS              RESTARTS   AGE
kube-system      coredns-d798c9dd-7zd8t        1/1     Running             0          70m
kube-system      helm-install-traefik-vzj29    0/1     Completed           0          70m
kube-system      traefik-65bccdc4bd-znjvg      1/1     Running             0          69m
metallb-system   speaker-7kxfh                 0/1     ContainerCreating   0          22s
metallb-system   speaker-nn778                 0/1     ContainerCreating   0          22s
metallb-system   speaker-cw756                 0/1     ContainerCreating   0          22s
metallb-system   speaker-448kf                 0/1     ContainerCreating   0          22s
metallb-system   controller-65895b47d4-6bnbr   0/1     ContainerCreating   0          22s
metallb-system   speaker-cw7vl                 1/1     Running             0          22s

모든 슬레이브 노드에 speaker가 설치된다.

MetalLB의 여러 설정이 있는데, 가장 기본적인 Layer 2 설정을 사용해 보자. 링크의 ConfigMap을 내 환경에 맞게 수정해서 등록하였다.

# metallb/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: default
      protocol: layer2
      addresses:
      - 192.168.129.240-192.168.129.250    

$ kubectl create -f configmap.yaml
configmap/config created

목표는 간단한 deployment를 생성한 후, 이를 서비스로 노출하여 외부로부터 접근하도록 만드는 것이다.

$ kubectl create -f nginx-example.yaml
deployment.apps/nginx-deployment created

$ kubectl expose deploy nginx-deployment
service/nginx-deployment exposed

$ kubectl get pod
NAME                                READY   STATUS              RESTARTS   AGE
nginx-deployment-68948fc4fc-qqktb   0/1     ContainerCreating   0          14s
nginx-deployment-68948fc4fc-96qrk   0/1     ContainerCreating   0          14s

$ kubectl get svc
NAME               TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
kubernetes         ClusterIP   172.24.0.1       <none>        443/TCP   75m
nginx-deployment   ClusterIP   172.25.208.104   <none>        80/TCP    8s

$ cat ingress-by-host/ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: testingress
  annotations:
    kubernetes.io/ingress.class: traefik
spec:
  rules:
  - host: g.cublr.com
    http:
      paths:
      - path: /
        backend:
          serviceName: nginx-deployment
          servicePort: 80

$ kubectl create -f ingress-by-host/ingress.yaml

ingress.extensions/testingress created

$ kubectl get svc
NAME               TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
kubernetes         ClusterIP   172.24.0.1       <none>        443/TCP   75m
nginx-deployment   ClusterIP   172.25.208.104   <none>        80/TCP    33s

$ kubectl get ing
NAME          HOSTS         ADDRESS           PORTS   AGE
testingress   g.cublr.com   192.168.129.240   80      10m