kubernetes snippets

How to deploy an app on a specific node/server in a kubernetes cluster using labels

Tagged kubernetes, label, node  Languages yaml

This is an example of how to deploy an app on a specific node/server in a kubernetes cluster using labels:

# # Label one node in k8s cluster
#
# $ kubectl label nodes 48.234.16.45 country=finland name=node1
#
# # Deploy 1 nginx pod in k8s cluster on node1 in Finland
#
# $ kubectl apply -f nginx.yml
#
# # View deployment
#
# $ kubectl describe deployment nginx-app
#
# # View pods
#
# $ kubectl get pods -l app=nginx
#
# # Find port the service is listening on
#
# $ kubectl describe service nginx-app | grep NodePort
# > NodePort:                 http   31796/TCP
# > NodePort:                 https  31797/TCP
#
# # Find the node the pod is deployed to
#
# $ kubectl describe pods nginx-app | grep Node
# > Node:           48.234.16.45/10.0.0.2
#
# # Access deployment using node ip and port
#
# http://<node ip>:<node port>
#
# # Export service to YAML
#
# $ kubectl get service nginx-app -o yaml --export
#
# # Delete
#
# $ kubectl delete deployments,services -l country=finland
#
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-app
  labels:
    run: nginx-app
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 1 # tells deployment to run 1 pods matching the template
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.13.12
        ports:
        - containerPort: 80
        - containerPort: 443
      nodeSelector:
        country: finland
        server: node1
---
#
# Expose deployment on <node ip>:<node port>. Node and a random port is assigned by k8s.
#
apiVersion: v1
kind: Service
metadata:
  labels:
    run: nginx-app
  name: nginx-app
spec:
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 80
  - name: https
    port: 443
    protocol: TCP
    targetPort: 443
  selector:
    app: nginx
  type: NodePort

How to connect to a Kubernetes cluster hosted on DigitalOcean

Tagged digitalocean, kubernetes  Languages bash

Tested April, 2019.

  1. Download the Kubernetes configuration from the DigitalOcean dashboard

  2. Move the Kubernetes configuration file to ~/.kube folder
$ mkdir $HOME/.kube/projectx/
$ mv ~/Downloads/projectx-staging-kubeconfig.yaml $HOME/.kube/projectx/staging-kubeconfig.yaml
  1. List all contexts in the KUBECONFIG variable
$ export KUBECONFIG=$HOME/.kube/projectx/staging-kubeconfig.yaml:$HOME/.kube/projectx/production-kubeconfig.yaml
  1. Install kubectl
$ brew install kubectl
  1. List context and nodes
$ kubectl config get-contexts
$ kubectl get nodes
$ kubectl config use-context

How to configure Kubernetes to pull images from a private Docker registry

Tagged docker, kubernetes, private, registry  Languages bash, yml

How to configure Kubernetes to pull images from a private Docker registry:

  • First configure Docker by following the steps outlined here:

https://snippets.aktagon.com/snippets/869-configure-docker-to-use-a-private-container-registry-using-a-self-signed-certificate

  • Verify that the Docker configuration contains the authentication information
sudo cat ~/.docker/config.json
{
    "auths": {
        "<registry-server>": {
            "auth": "<hash>"
        }
    },
    "HttpHeaders": {
        "User-Agent": "Docker-Client/18.09.4 (linux)"
    }
}
  • Base64 encode the config.json file
cat ~/.docker/config.json | base64 -w0 > config.base64.json
  • Create secret.yml and add the contents of config.base64.json to dockerconfigjson
apiVersion: v1
kind: Secret
metadata:
 name: registrypullsecret
data:
 .dockerconfigjson: <config.base64.json>
type: kubernetes.io/dockerconfigjson
  • Import the secret into Kubernetes
kubectl create -f secret.yml && kubectl get secrets
  • Test that the secret was imported into Kubernetes
kubectl get secrets

How to debug CrashLoopBackOff

Tagged crashloopbackoff, kubectl, kubernetes  Languages bash, yaml

One day, you see CrashLoopBackOff in the kubectl output:

$ kubectl get pod
NAME                               READY   STATUS             RESTARTS   AGE
app-548c9ddc46-z2fng               0/1     CrashLoopBackOff   79         6h26m

You already know that executing bash in the container is not possible because the container has crashed:

$ kubectl exec -ti app-548c9ddc46-z2fng bash
error: unable to upgrade connection: container not found ("app")

Option 1: Analyze the container logs

You can view the container’s logs with kubectl logs:

$ kubectl logs -f app-548c9ddc46-z2fng

Option 2: Modify Dockerfile’s CMD

Modifying the Dockerfile’s ‘CMD’ is not needed, as it can be done indirectly through the Pod’s YAML configuration file:

apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
    - name: app
      image: company/app
      # DEBUG env variables
      command: [ "/bin/sh", "-c", "env" ]

The modified command will print the environment variables to the logs:

command: [ "/bin/sh", "-c", "env" ]

To view the output run:

$ kubectl logs -f app-548c9ddc46-z2fng

Option 3: Start a shell and sleep (CMD)

Sleeping usually helps, and this can be done by modifying the container’s command:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: xxx-service
spec:
  replicas: 1
  template:
    ...
    spec:
      containers:
      - image: yyy/xxx:1.0.0
        name: xxx-service
        ...
        command:
          - "sh"
          - "-c"
          - "sleep 10000"

The container will start and run “sleep 10000” in a shell, giving you exactly 10000 seconds to debug the issue by connecting to the “sleeping” container:

$ kubectl exec -ti app-548c9ddc46-z2fng bash

How to set up a Digital Ocean Kubernetes cluster

Tagged digitalocean, kubernetes, setup  Languages bash, yaml

How to set up a Digital Ocean Kubernetes cluster

Introduction

Overview of how a request gets from a browser to a Docker container managed by Kubernetes:

Internet[Browser => DigitalOcean LoadBalancer] => Kubernetes[Ingress => Service => Deployment => Pod] => Docker[Container]

Prerequisites

  • Install kubectl
$ brew install kubectl
  1. Create cluster in DigitalOcean dashboard

Download the cluster configuration (YAML file) and put it in the ~/.kube folder.

  1. Set KUBECONFIG environment variable
$ export KUBECONFIG=/Users/christian/.kube/staging-kubeconfig.yaml
$ kubectl config current-context
$ kubectl get nodes
NAME               STATUS   ROLES    AGE   VERSION
xxx-staging-qv72   Ready    <none>   70m   v1.14.1
xxx-staging-qv7p   Ready    <none>   71m   v1.14.1
xxx-staging-qv7s   Ready    <none>   71m   v1.14.1
  1. Install ingress controller
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/cloud-generic.yaml

Get the EXTERNAL-IP of the load balancer:

$ kubectl get services --namespace=ingress-nginx
  1. Create ingress resource

ingress.yaml:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: app-ingress
  annotations:
    ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - http:
      paths:
        - path: /
          backend:
            serviceName: app-service
            servicePort: 80
$ kubectl apply -f ingress.yml
  1. Create deployment

deployment.yaml:

apiVersion: v1
kind: Service
metadata:
  name: app-service
spec:
  ports:
  - port: 80
    targetPort: 5678
  selector:
    app: app
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
spec:
  selector:
    matchLabels:
      app: app
  replicas: 1
  template:
    metadata:
      labels:
        app: app
    spec:
      containers:
      - name: app
        image: hashicorp/http-echo
        args:
        - "-text=Hello. This is your Digital Ocean k8s cluster."
        ports:
        - containerPort: 5678
$ kubectl apply -f deployment.yml
  1. Curl your app
curl https://<EXTERNAL-IP> --insecure

References