# # Install k3s # curl -sfL https://get.k3s.io | K3S_CLUSTER_INIT=1 INSTALL_K3S_EXEC="--disable=servicelb" sh - cat /var/lib/rancher/k3s/server/node-token # Run on other nodes to join the cluster curl -sfL https://get.k3s.io | \ INSTALL_K3S_EXEC=server \ K3S_URL=https://192.168.50.203:6443 \ K3S_TOKEN=... \ sh - kubectl get nodes --watch journalctl --unit=k3s kubectl get all --all-namespaces # # Install dashboard # GITHUB_URL=https://github.com/kubernetes/dashboard/releases VERSION_KUBE_DASHBOARD=$(curl -w '%{url_effective}' -I -L -s -S ${GITHUB_URL}/latest -o /dev/null | sed -e 's|.*/||') echo $VERSION_KUBE_DASHBOARD kubectl create -f https://raw.githubusercontent.com/kubernetes/dashboard/${VERSION_KUBE_DASHBOARD}/aio/deploy/recommended.yaml cat>dashboard.admin-user.yml<<"EOF" apiVersion: v1 kind: ServiceAccount metadata: name: admin-user namespace: kubernetes-dashboard EOF cat>dashboard.admin-user-role.yml<<"EOF" apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: admin-user roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: admin-user namespace: kubernetes-dashboard EOF kubectl create -f dashboard.admin-user.yml -f dashboard.admin-user-role.yml kubectl get all --all-namespaces # Connect to node again, but with your port 8001 forwarded. ssh -L 8001:127.0.0.1:8001 user1@ubuntutest1 kubectl proxy # Open in browser: http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/ kubectl --namespace kubernetes-dashboard describe secret admin-user-token | grep ^token # # Install MetalLB # GITHUB_URL=https://github.com/metallb/metallb/releases VERSION=$(curl -w '%{url_effective}' -I -L -s -S ${GITHUB_URL}/latest -o /dev/null | sed -e 's|.*/||') echo $VERSION kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/$VERSION/manifests/namespace.yaml kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/$VERSION/manifests/metallb.yaml kubectl create secret generic -n metallb-system memberlist --from-literal=secretkey="$(openssl rand -base64 128)" cat>metallb-configmap.yml<<"EOF" apiVersion: v1 kind: ConfigMap metadata: namespace: metallb-system name: config data: config: | address-pools: - name: default protocol: layer2 addresses: - 192.168.50.20-192.168.50.40 EOF kubectl apply -f metallb-configmap.yml # Check logs for errors kubectl logs -lapp=metallb --namespace metallb-system --all-containers=true --prefix -f # # Install docker registry # apt-get install docker-compose docker run -d -p 5000:5000 --restart=always --name registry registry docker ps -a # On each node: mkdir -p /etc/rancher/k3s/ cat>/etc/rancher/k3s/registries.yaml<<"EOF" mirrors: "ubuntutest1:5000": endpoint: - "http://ubuntutest1:5000" EOF systemctl restart k3s # # Create containerized app # mkdir -p /home/user1/dev/myapp1 cd /home/user1/dev/myapp1 cat>main.go<<"EOF" package main import ( "github.com/gorilla/mux" "html/template" "log" "net/http" "os" "time" ) var helloTemplate, _ = template.New("").Parse(`<!DOCTYPE html> <html> <head><title>testapp</title></head> <body> <h1>Test 1</h1> <p>Now: {{.now.Format "2006-01-02 15:04:05" }}</p> <p>Served from node: {{ .node }}</p> <p>Served from pod: {{ .pod }}</p> </body> </html> `) type Msg struct { Ts time.Time `json:"ts"` } func helloGet(w http.ResponseWriter, r *http.Request) { v := map[string]interface{}{ "now": time.Now(), "node": os.Getenv("NODE_NAME"), "pod": os.Getenv("POD_NAME"), } helloTemplate.Execute(w, v) } func main() { log.Println("Starting") router := mux.NewRouter() router.HandleFunc("/", helloGet).Methods("GET") handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { log.Println(r.Method + " " + r.URL.String()) router.ServeHTTP(w, r) }) log.Fatal(http.ListenAndServe(":8080", handler)) } EOF cat>go.mod<<"EOF" module myapp1 EOF touch go.sum cat>Dockerfile<<"EOF" FROM golang as builder WORKDIR /app COPY . ./ RUN go mod download RUN CGO_ENABLED=0 GOOS=linux go build -v -o server FROM alpine RUN apk add --no-cache ca-certificates COPY --from=builder /app/server /server CMD ["/server"] EOF docker build -t "myapp1" . docker run -it --rm -p 8080:8080 myapp1 docker tag myapp1 ubuntutest1:5000/myapp1:v1 docker push ubuntutest1:5000/myapp1:v1 curl -X GET ubuntutest1:5000/v2/_catalog curl -X GET ubuntutest1:5000/v2/myapp1/tags/list # # Create and deploy our app in k8s # mkdir -p /home/user1/dev/myapp1/k8s cd /home/user1/dev/myapp1 cat>k8s/deployment.yml<<"EOF" apiVersion: apps/v1 kind: Deployment metadata: name: myapp1-deployment spec: selector: matchLabels: app: myapp1 replicas: 3 template: metadata: labels: app: myapp1 spec: containers: - name: myapp1 image: ubuntutest1:5000/myapp1:v1 ports: - containerPort: 8080 env: - name: NODE_NAME valueFrom: fieldRef: fieldPath: spec.nodeName - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name topologySpreadConstraints: - maxSkew: 1 topologyKey: "kubernetes.io/hostname" whenUnsatisfiable: DoNotSchedule labelSelector: matchLabels: app: myapp1 EOF kubectl apply -f k8s/deployment.yml cat>k8s/service.yml<<"EOF" kind: Service apiVersion: v1 metadata: name: myapp1-service spec: type: ClusterIP selector: app: myapp1 ports: - name: http-myapp1 protocol: TCP port: 8080 EOF kubectl apply -f k8s/service.yml # Expose app via HTTP proxy (aka. "ingress") cat>k8s/ingress.yml<<"EOF" apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: myapp1-ingress spec: rules: - http: paths: - path: / pathType: Prefix backend: service: name: myapp1-service port: number: 8080 EOF kubectl apply -f k8s/ingress.yml kubectl logs -lapp=myapp1 --all-containers=true --prefix -f # # Upgrading to a new image. Either use this command or update the same field in deployment.yml. # cd /home/user1/dev/myapp1 docker build -t "myapp1" . docker tag myapp1 ubuntutest1:5000/myapp1:v2 docker push ubuntutest1:5000/myapp1:v2 kubectl set image deployments/myapp1-deployment myapp1=ubuntutest1:5000/myapp1:v2 kubectl rollout status deployments/myapp1-deployment # Rolling back (calling repeatedly switches between two newest versions). kubectl rollout undo deployments/myapp1-deployment # # Testing HA # kubectl get nodes ; kubectl get pod -o=custom-columns=NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName --all-namespaces kubectl drain ubuntutest1 --ignore-daemonsets --delete-emptydir-data kubectl uncordon ubuntutest1
Friday, February 12, 2021
Create a local Kubernetes cluster and deploy your code end to end
These are the commands accompanying the video tutorial I've made on how to create a local Kubernetes cluster and deploy a simple stateless app from code, end to end. You can find the video tutorial here: https://youtu.be/MZr9Ls38uPw .
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment