---
# System prepended metadata

title: JEDI 絕地武士
tags: [K8S]

---

# JEDI 絕地武士
## JEDI 功能介紹
* 透過 jedi pod 讓我們可以在這個 pod 對整個 k8s 做操作，並且本身擁有 regisry 功能，可以存放 k8s 所需使用的 image
* kadm container 為控制整個 k8s，並且可以 build image
* dkreg 為 image registry

## Dockerfile 設計
```
FROM taiwanese/alpine
RUN apk update && apk upgrade && apk add --no-cache nano sudo wget curl \
    tree elinks bash shadow procps util-linux git coreutils binutils jq \
    findutils grep openssh-server tzdata openrc tzdata fuse-overlayfs podman skopeo buildah k9s openssl && \
    apk add s3fs-fuse --no-cache --repository http://dl-3.alpinelinux.org/alpine/edge/community/ --allow-untrusted && \
    apk add mailcap --update-cache --repository http://dl-3.alpinelinux.org/alpine/edge/main/ --allow-untrusted && \
    apk add kubectl --update-cache --repository http://dl-3.alpinelinux.org/alpine/edge/community/ --allow-untrusted
    # 設定時區
COPY system.sh /usr/bin/system.sh
COPY secretcreate.sh /home/bigred/bin/secretcreate.sh
RUN cp /usr/share/zoneinfo/Asia/Taipei /etc/localtime && \
    ssh-keygen -t rsa -P "" -f /etc/ssh/ssh_host_rsa_key && \
    echo -e 'Welcome to KAdmin Console' > /etc/motd && \
    # 建立管理者帳號 bigred
    echo -e 'bigred\nbigred' | adduser -s /bin/bash -h /home/bigred -G wheel bigred && \
    mkdir /home/bigred/.ssh && chown bigred:wheel /home/bigred/.ssh && \
    echo "%wheel   ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers && \
    rm /sbin/reboot && rm /usr/bin/killall && echo "Port 22100" >> /etc/ssh/sshd_config && \
    mkdir /home/bigred/.kube && \
    echo "export PATH=/home/bigred/bin:$PATH" >> /etc/profile && \
    echo "source <(kubectl completion bash)" >> /etc/profile && \
    echo "source /usr/bin/system.sh" >> /etc/profile && \
    curl https://dl.min.io/client/mc/release/linux-amd64/mc --create-dirs -o /home/bigred/bin/mc && \
    chmod +x /home/bigred/bin/mc
    
EXPOSE 22100

ENTRYPOINT ["/usr/sbin/sshd"]
CMD ["-D"]
```
## `secretcreate.sh`
```
#!/bin/bash

if [[ -z "$1" ]]; then
  echo "Please enter the namespace name!" && exit 0
else
  sudo podman login --tls-verify=false -u docker -p $DKREGPW $DKRESVC:5000 &>/dev/null
  sudo cp /run/containers/0/auth.json /home/bigred/auth.json; sudo chmod 755 /home/bigred/auth.json
  for ns in $@
  do
    if ! kubectl get ns "$ns" &>/dev/null; then
      sudo podman logout $DKRESVC:5000 &>/dev/null
      sudo rm /home/bigred/auth.json
      echo "$ns namespace not found!" && exit 0
    fi
    if kubectl get secret dkreg -n "$ns" &>/dev/null; then
      kubectl delete secret dkreg -n "$ns" &>/dev/null
      kubectl create secret generic dkreg -n "$ns" --from-file=.dockerconfigjson=/home/bigred/auth.json --type=kubernetes.io/dockerconfigjson &>/dev/null
      kubectl patch serviceaccount default -n "$ns" -p '{"imagePullSecrets": [{"name": "dkreg"}]}' &>/dev/null
      echo "$ns namespace imagePullSecrets is change!"
    else
      kubectl create secret generic dkreg -n "$ns" --from-file=.dockerconfigjson=/home/bigred/auth.json --type=kubernetes.io/dockerconfigjson &>/dev/null
      kubectl patch serviceaccount default -n "$ns" -p '{"imagePullSecrets": [{"name": "dkreg"}]}' &>/dev/null
      echo "$ns namespace imagePullSecrets ok!"
    fi
  done
  sudo podman logout $DKRESVC:5000 &>/dev/null
  sudo rm /home/bigred/auth.json
fi
```
## `system.sh` 腳本

```
$ cat /usr/bin/system.sh
export POD_NAMESPACE=default
export KUBERNETES_SERVICE_PORT=443
export KUBERNETES_SERVICE_HOST=kubernetes.default
export KUBERNETES_SERVICE_PORT_HTTPS=443
export JEDIPODNAME=$(kubectl -n kube-system get po | grep jedi | cut -d ' ' -f1)
export DKRESVC=$(kubectl -n kube-system get svc jedi | tail -n 1 | tr -s \ - | cut -d ' ' -f3)
export DKREGPW=$(kubectl -n kube-system logs $JEDIPODNAME -c dkreg| grep 'user=docker' | cut -d '=' -f6 | cut -d ' ' -f1 | tr -d '"')

alias kg='kubectl get'
alias ka='kubectl apply'
alias kd='kubectl delete'
alias kt='kubectl top'
alias ks='kubectl get all -n kube-system'
alias kt='kubectl top'
alias kk='kubectl krew'
alias k='kubectl'

export PS1='\u@\h:\w$ '
alias pingdup='sudo arping -D -I eth0 -c 2 '
alias ping='ping -c 4'
alias dir='ls -alh'
alias docker='sudo /usr/bin/podman'

echo 'bigred:100000:65535' | sudo tee /etc/subuid &>/dev/null
echo 'bigred:100000:65535' | sudo tee /etc/subgid &>/dev/null


if [ "$USER" == "bigred" ]; then
   kubectl get secret 2>/dev/null | grep dkreg &>/dev/null
   if [ "$?" != "0" ]; then
     sudo podman login --tls-verify=false -u docker -p $DKREGPW $DKRESVC:5000 &>/dev/null
     sudo cp /run/containers/0/auth.json /home/bigred/auth.json; sudo chmod 755 /home/bigred/auth.json
     kubectl create secret generic dkreg -n default --from-file=.dockerconfigjson=/home/bigred/auth.json --type=kubernetes.io/dockerconfigjson &>/dev/null
     kubectl create secret generic dkreg -n kube-public --from-file=.dockerconfigjson=/home/bigred/auth.json --type=kubernetes.io/dockerconfigjson &>/dev/null
     echo "dkreg secret ok (namespace: default, kube-public)"

     kubectl patch serviceaccount default -n default -p '{"imagePullSecrets": [{"name": "dkreg"}]}' &>/dev/null
     kubectl patch serviceaccount default -n kube-public -p '{"imagePullSecrets": [{"name": "dkreg"}]}' &>/dev/null
     echo "imagePullSecrets ok (namespace: default, kube-public)"

     sudo podman logout $DKRESVC:5000 &>/dev/null
     sudo rm /home/bigred/auth.json
   else
     sudo podman login --tls-verify=false -u docker -p $DKREGPW $DKRESVC:5000 &>/dev/null
     sudo cp /run/containers/0/auth.json /home/bigred/auth.json; sudo chmod 755 /home/bigred/auth.json
     for ns in default kube-public
     do
       old=$(kubectl -n $ns get secret dkreg -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d)
       new=$(sudo cat /run/containers/0/auth.json)
       if [[ "$old" != "$new" ]]; then
         kubectl delete secret dkreg -n "$ns" &>/dev/null
         kubectl patch serviceaccount default -n "$ns" -p '{"imagePullSecrets": [{"name": "dkreg"}]}' &>/dev/null
         echo "imagePullSecrets is change (namespace: $ns)"
       else
         echo "imagePullSecrets is ok (namespace: $ns)"
       fi
     done
     sudo podman logout $DKRESVC:5000 &>/dev/null
     sudo rm /home/bigred/auth.json
   fi

   if [[ ! -d ~/.krew ]]; then
     curl -fsSLO "https://github.com/kubernetes-sigs/krew/releases/download/v0.4.4/krew-linux_amd64.tar.gz" &>/dev/null
     tar zxvf krew-linux_amd64.tar.gz &>/dev/null
     ./krew-linux_amd64 install krew &>/dev/null
     rm krew-linux_amd64.tar.gz krew-linux_amd64 LICENSE &>/dev/null
   fi

   kubectl get pod --field-selector=status.phase==Succeeded -A 2>/dev/null | grep Completed &>/dev/null
   if [ "$?" == "0" ]; then
      kubectl delete pod --field-selector=status.phase==Succeeded -A &>/dev/null
      [ "$?" == "0" ] && echo "delete all completed pods"

      kubectl delete pod --field-selector=status.phase==Failed -A &>/dev/null
      [ "$?" == "0" ] && echo "delete all errored pods"
      echo ""
   fi
fi
```

## 部屬
* 產生 ssh key 憑證
```
$ ssh-keygen -t rsa -P ""

$ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
```
```
$ cd ~;kubectl -n kube-system create secret generic kadm-sshkey --from-file=.ssh/authorized_keys
```
```
$ kubectl -n kube-system get secret kadm-sshkey
NAME          TYPE     DATA   AGE
kadm-sshkey   Opaque   1      42s
```

* clusterIP、nodeName 需根據自己的 podCIDR 與主機名做變更
* jedi 必須建立在 kube-system namespace
* 使用 deployment 方式建立
* 透過 ClusterRole 賦予這個 pod 有最高權限
```
# roleRef 為引用哪一個 serviceaccount 的權限
# subjects 將權限綁定到指定 serviceaccount
$ echo 'apiVersion: v1
kind: ServiceAccount
metadata:
  name: kube-kadm
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: kube-kadm
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: kube-kadm
  namespace: kube-system
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: jedi
  namespace: kube-system
  labels:
    app: jedi
spec:
  replicas: 1
  selector:
    matchLabels:
      app: jedi
  template:
    metadata:
      labels:
        app: jedi
    spec:
      volumes:
      - name: kadm-storage
        hostPath:
          path: /opt
      - name: ssh-volume
        secret:
          secretName: kadm-sshkey
      - name: dkreg-storage
        hostPath:
          path: /opt/dkreg
      serviceAccountName: kube-kadm
      initContainers:
      - name: init-myservice 
        image: taiwanese/jedi
        imagePullPolicy: IfNotPresent
        volumeMounts:
        - mountPath: "/opt"
          name: kadm-storage
        command: 
          - /bin/sh
          - -c
          - |
            if [[ -f /opt/dkreg/htpasswd ]]; then
              sudo rm /opt/dkreg/htpasswd
            fi
      containers:
      - name: kadm
        image: taiwanese/jedi
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 22100
        volumeMounts:
        - name: kadm-storage
          mountPath: /opt
        - name: ssh-volume
          mountPath: "/etc/sshkey"
        securityContext:
          privileged: true
        lifecycle:
            postStart:
              exec:
                command:
                  - /bin/sh
                  - -c
                  - |
                    cp /etc/sshkey/authorized_keys /home/bigred/.ssh/authorized_keys
      - image: registry:2
        name: dkreg
        ports:
        - containerPort: 5000
          hostPort: 5000
        volumeMounts:
        - mountPath: "/var/lib/registry"
          name: dkreg-storage
        env:
        - name: REGISTRY_AUTH
          value: "htpasswd"
        - name: REGISTRY_AUTH_HTPASSWD_PATH
          value: "/var/lib/registry/htpasswd"
        - name: REGISTRY_AUTH_HTPASSWD_REALM
          value: "Registry Realm"
        - name: REGISTRY_STORAGE_DELETE_ENABLED
          value: "true"
      nodeName: w1                                # change
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: jedi
  name: jedi
  namespace: kube-system
spec:
  clusterIP: 10.21.0.11                            # change
  ports:
  - name: dkregistry
    port: 5000
    protocol: TCP
    targetPort: 5000
  - name: kadm
    port: 22100
    protocol: TCP
    targetPort: 22100
  selector:
    app: jedi
  type: ClusterIP' | kubectl apply -f -
```

## 登入 kadm

* 使用 ssh 方式登入
```
$ ssh bigred@10.21.0.11 -p 22100
Welcome to KAdmin Console
dkreg secret ok (namespace: default, kube-public)
imagePullSecrets ok (namespace: default, kube-public)
Install mc command
MinIO mc ok
Install krew command
kubectl krew ok
bigred@jedi-5bb596699d-b6vc8:~$ kubectl get no
NAME      STATUS   ROLES                              AGE    VERSION
m1        Ready    control-plane,etcd,master,worker   101d   v1.26.8+rke2r1
w1        Ready    worker                             92d    v1.26.8+rke2r1

# 也可以 pull image 與 image 製作
bigred@jedi-5bb596699d-b6vc8:~$ sudo podman pull nginx
Resolving "nginx" using unqualified-search registries (/etc/containers/registries.conf)
Trying to pull docker.io/library/nginx:latest...
```

