Deploying on Kubernetes #4: The deployment object

Assumptions

To read this it’s expected that you’re familiar with Docker, and have perhaps played with building docker containers. Additionally, some experience with docker-compose is perhaps useful, though not immediately related.

Necessary Background

So far we’ve been able:

  1. Create the helm chart to manage the resources
  2. Add the MySQL and Redis dependencies

Managing Deployments

  1. Create a clean upgrade path between the versions
  2. Deploy that version of the software somewhere in parallel or on top of the existing software
  3. (if required) delete the old version of the software
  4. Repeat
  • The application is a critical bug that wasn’t caught during QA
  • The application is incompatible with something else stored in the production environment
  • The application is having a bad day

Containers

Part of the solution to making software deployment a reliable, repeatable process is solved by “containers”. From the Docker website:

  • The application is incompatible with something else stored in the production environment (it’s packaged in the container — it is compatible by design)

Kubernetes

From the Kubernetes website:

  • Scaling the software deployment
  • Handling the failure of the software, hardware, network or other components between

The Deployment Object

From our earlier posts, we know that we have deployed MySQL and Redis onto a Kubernetes cluster. But we haven’t yet deployed an actual instance of kolide/fleet . That’s the next step! Hooray!

$ kubectl get deploymentsNAME                 DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
kolide-fleet-mysql 1 1 1 1 22h
kolide-fleet-redis 1 1 1 1 22h
$ kubectl get deployment kolide-fleet-redis --output=yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
creationTimestamp: 2018-03-27T16:25:08Z
generation: 1
labels:
app: kolide-fleet-redis
chart: redis-1.1.21
heritage: Tiller
release: kolide-fleet
name: kolide-fleet-redis
namespace: default
resourceVersion: "889"
selfLink: /apis/extensions/v1beta1/namespaces/default/deployments/kolide-fleet-redis
uid: 69f8140c-31db-11e8-81e0-080027c1d0f5
spec:
replicas: 1
selector:
matchLabels:
app: kolide-fleet-redis
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app: kolide-fleet-redis
spec:
containers:
- env:
- name: REDIS_PASSWORD
valueFrom:
secretKeyRef:
key: redis-password
name: kolide-fleet-redis
- name: REDIS_DISABLE_COMMANDS
value: FLUSHDB,FLUSHALL
image: bitnami/redis:4.0.9-r0
imagePullPolicy: IfNotPresent
livenessProbe:
exec:
command:
- redis-cli
- ping
failureThreshold: 3
initialDelaySeconds: 30
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
name: kolide-fleet-redis
ports:
- containerPort: 6379
name: redis
protocol: TCP
readinessProbe:
exec:
command:
- redis-cli
- ping
failureThreshold: 3
initialDelaySeconds: 5
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
resources:
requests:
cpu: 100m
memory: 256Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /bitnami
name: redis-data
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext:
fsGroup: 1001
runAsUser: 1001
terminationGracePeriodSeconds: 30
volumes:
- name: redis-data
persistentVolumeClaim:
claimName: kolide-fleet-redis
status:
availableReplicas: 1
conditions:
- lastTransitionTime: 2018-03-27T16:25:08Z
lastUpdateTime: 2018-03-27T16:25:08Z
message: Deployment has minimum availability.
reason: MinimumReplicasAvailable
status: "True"
type: Available
observedGeneration: 1
readyReplicas: 1
replicas: 1
updatedReplicas: 1
image: bitnami/redis:4.0.9-r0
imagePullPolicy: IfNotPresent
- lastTransitionTime: 2018-03-27T16:25:08Z
lastUpdateTime: 2018-03-27T16:25:08Z

My own personal deployment

The deployment specification I will be starting with is the one from the starter chart. I’m not going to paste it in it’s entirety as it’s .. rather large, but instead approach it in sections. You can check out the full spec on GitHub. If you know about each section — skip it.

Metadata

An example of this section is below:

apiVersion: "apps/v1"
kind: "Deployment"
metadata:
labels:
app: {{ template "fleet.fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
heritage: "{{ .Release.Service }}"
release: "{{ .Release.Name }}"
name: {{ template "fleet.fullname" . }}
apiVersion: "apps/v1"
kind: "Deployment"
metadata:
labels:
app: {{ template "fleet.fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
heritage: "{{ .Release.Service }}"
release: "{{ .Release.Name }}"
name: {{ template "fleet.fullname" . }}
  • Name
$ kubectl get all --selector app=kolide-fleet-mysql
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deploy/kolide-fleet-mysql 1 1 1 1 23h
NAME DESIRED CURRENT READY AGE
rs/kolide-fleet-mysql-6c859797b4 1 1 1 23h
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deploy/kolide-fleet-mysql 1 1 1 1 23h
NAME DESIRED CURRENT READY AGE
rs/kolide-fleet-mysql-6c859797b4 1 1 1 23h
NAME READY STATUS RESTARTS AGE
po/kolide-fleet-mysql-6c859797b4-gf6lk 1/1 Running 1 23h
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
svc/kolide-fleet-mysql ClusterIP 10.104.173.216 <none> 3306/TCP 23h
"{{ .Chart.Name }}-{{ .Chart.Version }}"

(Deployment) Spec

The spec node is the meat of the deployment. It is where the behaviour of the object is defined.

spec:
replicas: {{ default 2 .Values.deployment.replicas }}
selector:
matchLabels:
# ... lots of other properties we'll approach shortly

Replicas

spec:
#
# Spec illustrated for orientation
#
replicas: {{ default 2 .Values.deployment.replicas }}
deployment:
replicas: 1
  1. Unless there is a value set in the Values.yml file. Then use that

Selector

From the Kubernetes docs:

selector:
matchLabels:
app: {{ template "fleet.fullname" . }}
release: "{{ .Release.Name }}"

Strategy

The strategy is what happens in the case of updates to the deployment specification. It looks like this:

strategy:
type: "RollingUpdate"
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
  1. Recreate, in which all existing pods are killed before a new release is started.

Template

template:
metadata:
# ... metadataa
spec:

(Pod) Metadata

template:
metadata:
labels:
app: {{ template "fleet.fullname" . }}
release: "{{ .Release.Name }}"
annotations:
# ..

(Pod) Spec + Containers

The pod specification the primary definition for how run containers on Kubernetes. A minimal spec looks like:

spec:
containers:
- name: fleet
image: {{ .Values.pod.fleet.image | quote }}
ports:
- containerPort: 8080
protocol: "TCP"
name: "http"
  • image is the name of the (usually Docker) container that will be used
  • ports is the ports that expect to be open

Restart Policy

restartPolicy: "Always"

In conclusion

The deployment object is suuper complex, but it is also among the most important specifications to become accustomed to as we’re developing applications for Kubernetes.

  • Liveness Probes
  • Resource Usage
  • Security Context

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store