YAML Config#
Kubernetes resources are primarily configured using YAML files. We’ve used the kubectl edit command to edit resources in the cluster on-demand, but let’s inspect our deployment’s YAML file a bit more closely.
Assignment#
First, download a copy of your deployment’s YAML file and save it in your current directory:
kubectl get deployment synergychat-web -o yaml > web-deployment.yamlThen open it in your text editor. There are 5 top-level fields in the file:
apiVersion: apps/v1- Specifies the version of the Kubernetes API you’re using to create the object (e.g., apps/v1 for Deployments).kind: Deployment- Specifies the type of object you’re configuringmetadata- Metadata about the deployment, like when it was created, its name, and its IDspec- The desired state of the deployment. Most impactful edits, like how many replicas you want, will be made here.status- The current state of the deployment. You won’t edit this directly, it’s just for you to see what’s going on with your deployment.
Inside your editor, change the number of replicas to 3 and save the file. Notice that you’re just editing a file on your machine! It won’t yet have any effect on the deployment in your cluster.
To apply the changes, run:
kubectl apply -f web-deployment.yamlYou should get a warning that lets you know that you’re missing the last-applied-configuration annotation. That’s okay! we got that warning because we created this deployment the quick and dirty way, by using kubectl create deployment instead of creating a YAML file and using kubectl apply -f.
However, because we’ve now updated it with kubectl apply, the annotation is now there, and we won’t get the warning again.
Download the YAML file again and take a look at it. You should see the annotation now.
Apply the configuration a second time, you won’t get the warning. Save this YAML file in a git repo for this course! We’ll be making more configuration files. Kubernetes is an “infra-as-code” tool, so it’s important to keep your configuration files in a git repo.
Create a Deployment Configuration#
Let’s write a deployment from scratch.
Feel free to reference the k8s docs here as you go for examples of the proper structure.
- Create a new file called
api-deployment.yaml. - Add the
apiVersionandkindfields. TheapiVersionisapps/v1and, since this is a deployment, thekindisDeployment. - Add a
metadata/namefield, and let’s name our deploymentsynergychat-apifor consistency. - Add a
metadata/labels/appfield, and also set it tosynergychat-api. This will be used to select the pods that this deployment manages. - Add a
spec/replicasfield and let’s set it to1. We can always scale up to more pods later. - Add a
spec/selector/matchLabels/appfield and set it tosynergychat-api. This should match the label we set in step 4. - Add a
spec/template/metadata/labels/appfield and set it tosynergychat-api. Again, this should match the label we set in step 4. Labels are important because they’re how Kubernetes knows which pods belong to which deployments. - Add a
spec/template/spec/containersfield. This actually contains a list of containers that will be deployed:- Note: A hyphen is how you denote a list item in YAML
- Set the
nameof the container tosynergychat-api. - Set the
imagetobootdotdev/synergychat-api:latest. This tells k8s where to download the Docker image from.
here’s the equivalent JSON:
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"name": "synergychat-api",
"labels": {
"app": "synergychat-api"
}
},
"spec": {
"replicas": 1,
"selector": {
"matchLabels": {
"app": "synergychat-api"
}
},
"template": {
"metadata": {
"labels": {
"app": "synergychat-api"
}
},
"spec": {
"containers": [
{
"name": "synergychat-api",
"image": "bootdotdev/synergychat-api:latest"
}
]
}
}
}
}Config Maps#
There are several ways to manage environment variables in Kubernetes. One of the most common ways is to use ConfigMaps. ConfigMaps allow us to decouple our configurations from our container images, which is important because we don’t want to have to rebuild our images every time we want to change a configuration value.
In a Dockerfile we can set environment variables like this:
ENV PORT=3000The trouble is, that means that everyone using that image will have to use port 3000. It also means that if we want to change the port, we have to rebuild the image.
Example#
First, let’s take a closer look at our crashing pod and try to figure out why it’s crashing.
kubectl get podsCopy the pod name and then get the logs:
kubectl logs <pod-name>You should see that a specific environment variable is missing! Let’s fix that.
Create a new file. Let’s call it api-configmap.yaml. Add the following YAML to it:
apiVersion:v1kind:ConfigMapmetadata/name:synergychat-api-configmapdata/API_PORT:"8080"
Next, apply the config map:
kubectl apply -f api-configmap.yamlNow, we haven’t yet connected the config map to our pod, so it should still be crashing. However, for now, let’s just validate that the config map was created successfully:
kubectl get configmapsApplying the Config Map#
Now that we have a config map, we need to connect it to our deployment.
Open up your api-deployment.yaml file. We’re going to add a few things to it. Under the containers section, add the following to the first (and only) entry:
env:
- name: API_PORT
valueFrom:
configMapKeyRef:
name: synergychat-api-configmap
key: API_PORTThis tells Kubernetes to set the API_PORT environment variable to the value of the API_PORT key in the synergychat-api-configmap config map. Reference the official docs if you’re confused about the structure of the yaml.
Next, apply the deployment. Hopefully, you remember the command for this by now.
Once it’s applied, you should be able to take a look at the pods and see that a new API pod has been deployed and isn’t crashing!
Let’s forward the API pod’s 8080 port to our local machine so we can test it out.
kubectl port-forward <pod-name> 8080:8080Make sure it returns a 404 response when you hit the root:
curl http://localhost:8080Config Maps Are Insecure#
ConfigMaps are a great way to manage innocent environment variables in Kubernetes. Things like:
- Ports
- URLs of other services
- Feature flags
- Settings that change between environments, like
DEBUGmode
However, they are not cryptographically secure. ConfigMaps aren’t encrypted, and they can be accessed by anyone with access to the cluster.
If you need to store sensitive information, you should use Kubernetes Secrets or a third-party solution. See the secrets chapter for a full walkthrough.
Crawler#
We’ve got one last application to deploy to our cluster: the crawler. This is an application that continuously crawls Project Gutenberg and exposes the juicy data that it finds via a JSON API.
Assignment#
Add a New Config Map#
Create a copy of your api-configmap.yaml file and call it crawler-configmap.yaml. We’re going to make a few changes to it.
- Name it
synergychat-crawler-configmapinstead ofsynergychat-api-configmap. - Remove the
API_PORTenvironment variable. - Add some new environment variables:
CRAWLER_PORT:"8080"CRAWLER_KEYWORDS:love,hate,joy,sadness,anger,disgust,fear,surprise
It’s okay that the CRAWLER_PORT in the crawler deployment is the same as the API_PORT in the api deployment. They’re in different pods, and these are pod-internal ports.
Here’s a reference to the docs for the SynergyChat microservices on GitHub in case you want additional info about the crawler.
Deploy the config map:
kubectl apply -f crawler-configmap.yamlAdd a New Deployment#
Create a copy of your api-deployment.yaml file and call it crawler-deployment.yaml. We’re going to make a few changes to it.
- Update all
synergychat-apireferences tosynergychat-crawler. - Update the image URL to
bootdotdev/synergychat-crawler:latest. - Update the environment variable references to match the new config map. (See below)
For the api service, we used this syntax to connect the config map to the deployment:
spec:
containers:
- image: bootdotdev/synergychat-api:latest
name: synergychat-api
env:
- name: API_PORT
valueFrom:
configMapKeyRef:
name: synergychat-api-configmap
key: API_PORTIf we use this same format, it gets kinda verbose and repetitive to list out each environment variable:
spec:
containers:
- image: bootdotdev/synergychat-api:latest
name: synergychat-api
env:
- name: THING_ONE
valueFrom:
configMapKeyRef:
name: synergychat-api-configmap
key: THING_ONE
- name: THING_TWO
valueFrom:
configMapKeyRef:
name: synergychat-api-configmap
key: THING_TWO
- name: THING_THREE
...We can use the envFrom key instead of the env key to reference the entire config map and make it available to the pods in the deployment:
envFrom:
- configMapRef:
name: synergychat-crawler-configmapOnce you’ve updated the deployment, apply it:
kubectl apply -f crawler-deployment.yamlIf the pod isn’t “ready”, check the logs to see if there’s an error. If the error is related to environment variables, debug your config map and deployment files and reapply them.
Once it’s ready, forward the pod’s 8080 port to your local machine:
kubectl port-forward <pod-name> 8080:8080for more secrets