Skip to content

Instantly share code, notes, and snippets.

@wmedlar
Last active April 24, 2020 19:24
Show Gist options
  • Save wmedlar/b2881740c0de571282b9f28bfd86541a to your computer and use it in GitHub Desktop.
Save wmedlar/b2881740c0de571282b9f28bfd86541a to your computer and use it in GitHub Desktop.
Quick Intro to Kubernetes Resources

Pods, services, deployments... it all sounds the same until you've had the chance to get hands on with it. This will be a short reference to the terminology of Kubernetes resources for a new cluster operator or developer.

Pods

Pods are one or more containers (but usually just one) running together; they are the smallest executable resource in Kubernetes.

Do not use pods directly, they don't scale and cannot be relocated to a different server. Use one of the below abstractions to manage templates of pods.

apiVersion: v1
kind: Pod
metadata:
  name: my-app
  labels:
    app.kubernetes.io/name: my-app
spec:
  containers:
  - name: server
    image: gcr.io/my-org/my-app:v1.2.3
    ports:
    - name: http
      containerPort: 8080

Containers in a pod share a network interface so they can communicate over localhost. They can also be configured to share a process namespace (.spec.shareProcessNamespace: true) which is useful in rare situations.

Pod Controllers

Pod controllers are higher-level abstractions that manage templates of pods to simplify scaling and management of applications. Most of these controllers create a ReplicaSet as an intermediary controller between themselves and the pods they manage; we can generally ignore these.

Deployments

Deployments are the simplest controller, they ensure that .spec.replicas copies of a pod are running at all times. Most applications are stateless and will be run as a deployment.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  labels:
    app.kubernetes.io/name: my-app
    app.kubernetes.io/part-of: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app.kubernetes.io/name: my-app
      app.kubernetes.io/managed-by: deployment/my-app
      app.kubernetes.io/part-of: my-app 
  template:
    metadata:
      labels:
        app.kubernetes.io/name: my-app
        app.kubernetes.io/managed-by: deployment/my-app
        app.kubernetes.io/part-of: my-app
    spec:
      containers:
      - name: server
        image: gcr.io/my-org/my-app:v1.2.3
        ports:
        - name: http
          containerPort: 8080

The above deployment will create three pods that look like the following.

apiVersion: v1
kind: Pod
metadata:
  name: my-app-b94bc5c87-5jdxm
  labels:
    app.kubernetes.io/name: my-app
    app.kubernetes.io/managed-by: deployment/my-app
    app.kubernetes.io/part-of: my-app
    pod-template-hash: b94bc5c87
  ownerReferences:
  - apiVersion: apps/v1
    blockOwnerDeletion: true
    controller: true
    kind: ReplicaSet
    name: my-app-b94bc5c87
    uid: d5afcfed-eb3e-4071-b659-535c6e1bbe7b
spec:
  containers:
  - name: server
    image: gcr.io/my-org/my-app:v1.2.3
    ports:
    - name: http
      containerPort: 8080

Some interesting things to note are the hash appended to the pod's name (b94bc5c87) which matches the pod-template-hash label and the name of a ReplicaSet in the pod's metadata.ownerReferences section. Pods with this same hash are from the same version of a deployment; other versions of a deployment (say we updated to v1.2.4 of the same container image) would have a different hash.

StatefulSets

StatefulSets perform a similar job as deployments but also provide some stateful guarantees:

  • numbered pod names that persist across versions (my-statefulset-0, my-statefulset-1, ... instead of hash suffixes)
  • consistent storage volume mounting (same pod gets same volume mounted across versions)
  • ordered rollouts (one pod at a time starting with the lowest number)

These are useful for clustered programs like databases, although I would recommend running third-party managed services in place of self-hosting them. Statefulsets are rare in normal development.

DaemonSets

DaemonSets also manage identical copies of pods, however they are limited by design to one pod per server. These are useful to run per-server process monitors (like the datadog agent) or an ingress controller to properly balance network traffic to nodes behind a load balancer.

Jobs

Jobs run pods until they complete successfully, with backoff logic a configurable number of retries. These are perfect for running pre-deploy and post-deploy tasks, like database backups and migrations.

CronJobs

CronJobs run pods (through jobs) automatically on an interval. These are great for running frequent tasks like batch jobs or nightly database backups (you can never have enough).

Configuration

Kubernetes contains configuration primitives that may be mounted into a container (see: configmaps and secrets) to control its behavior without being built into the container's image. Both can also be injected into a container's environment.

ConfigMaps

Configmaps contain plaintext key-value pairs and files.

apiVersion: v1
kind: ConfigMap
metadata:
  name: my-app-config
  labels:
    app.kubernetes.io/name: my-app-config
    app.kubernetes.io/part-of: my-app
data:
  some-key: some-value
  a-file.json: |
    {"this is a json file": "embedded within a kubernetes manifest"}

Secrets

Secrets contain, as their name might suggest, sensitive values and files. These are not encrypted in any way, they are simply base64-encoded to contain binary data.

The following secret has data equivalent to the above configmap.

apiVersion: v1
kind: Secret
metadata:
  name: my-app-config
  labels:
    app.kubernetes.io/name: my-app-config
    app.kubernetes.io/part-of: my-app
data:
  some-key: c29tZS12YWx1ZQ==
  a-file.json: eyJ0aGlzIGlzIGEganNvbiBmaWxlIjogImVtYmVkZGVkIHdpdGhpbiBhIGt1YmVybmV0ZXMgbWFuaWZlc3QifQ==

Pod Networking

Under Kubernetes networking each pod gets its own in-cluster IP and DNS name. Because pods are ephemeral it is beter to use the following abstractions when making network calls between each other.

Services

Services are load balancers for pods. They select pods by their labels; a service's .spec.selector should match a pod's .metadata.labels. Be strict with your label selectors, a pod must match all of them to be included in the service's load balancing, but the service will select any and all pods that match the selector, possibly including unintentional ones.

apiVersion: v1
kind: Service
metadata:
  name: my-app
  labels:
    app.kubernetes.io/name: my-app
    app.kubernetes.io/part-of: my-app
spec:
  ports:
  - name: http
    port: 8080
    targetPort: http
  selector:
    app.kubernetes.io/name: my-app
    app.kubernetes.io/managed-by: deployment/my-app
    app.kubernetes.io/part-of: my-app
  type: ClusterIP

Endpoints

Services create Endpoints resources automatically, which can be inspected to reveal exactly which pods a service is selecting. These are included in this list because of their usefulness when debugging, you will almost never create endpoints directly.

apiVersion: v1
kind: Endpoints
metadata:
  name: my-app
  labels:
    app.kubernetes.io/name: my-app
    app.kubernetes.io/part-of: my-app
subsets:
- addresses:
  - ip: 10.0.1.222
    nodeName: gke-my-cluster-my-node-a8764c1c-1drj
    targetRef:
      kind: Pod
      name: my-app-b94bc5c87-5jdxm
      namespace: default
  ports:
  - name: http
    port: 8080
    protocol: TCP

Ingress

Ingress resources map external hostnames to services (which are, generally, only accessible within the cluster), allowing them to be exposed to the public internet. Ingresses are managed by an "ingress controller", the complexities of which are described in another document, but it can generally be thought of as a Kubernetes-native reverse proxy.

Ingresses route hostname and path prefix (.spec.rules[].host and .spec.rules[].http.paths[].path respectively) matches to selected services within the same namespace by their names and ports (.spec.rules[].http.paths[].backend.serviceName and servicePort respectively). In the following example, any request to foo.bar.com/ will be routed to svc/my-app's http port.

The .spec.tls stanza controls TLS termination, mapping a collection of hostnames to a secret containing the corresponding TLS certificate and private key. The stanza can be omitted entirely if TLS termination is handled elsewhere in the network.

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: foo-bar-com
  labels:
    app.kubernetes.io/name: foo.bar.com
    app.kubernetes.io/part-of: my-app
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - backend:
          serviceName: my-app
          servicePort: http
        path: /
  tls:
  - hosts:
    - foo.bar.com
    secretName: foo-bar-com-tls
status:
  loadBalancer:
    ingress:
    - ip: 34.0.0.0

DNS is managed separately, foo.bar.com must still point to the exposed ingress controller.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment