In this scenario you'll run a Go application in a Kubernetes cluster that connects to a database service for storing state information.
These exercises have been tests in the single node Kubernetes cluster that is set up for you here in Katacoda, but you should also be able to run the same exercises using the Kubernetes support in Docker for Mac/Windows on your laptop if you prefer.
You have run a stateless web application in Kubernetes. Your app stores its data in a database that is run in a separate database service. Your application code doesn't need to know the IP address for the database, which could be running anywhere in the cluster. The application only needs to know the service DNS name and port in order to connect to the database.
Kubernetes stateless applications
Create a database service
It's very likely that your application code will need to communicate with other containerized code in the same Kubernetes cluster. Kubernetes makes networking your containers together very easy, using DNS.
In this step you will deploy a service for a database, and modify your app code so that it uses the database.
The application will return the number of requests or "hits" that it has received. The number of hits is maintained in a database.
Here's a deployment file that will run Postgres for you.
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: postgres spec: template: metadata: labels: app: postgres spec: containers: - image: "postgres:10.1" name: postgres envFrom: - configMapRef: name: pg-config ports: - containerPort: 5432 name: postgres volumeMounts: - name: postgres-storage mountPath: /var/lib/postgresql/data volumes: - name: postgres-storage hostPath: path: /var/lib/pg/data
- You can use a pre-existing container image for Postgres
- This file refers to a configMap - this is coming up next
- This deployment uses a
hostPathvolume, which means the containers in this deployment can access a directory on the host node. This will work for our demonstration purposes today, because we only have one node. In a production deployment you would have your containers use other types of storage
The deployment refers to a ConfigMap, which is a way of passing environment variables into a container. Let's define that next.
apiVersion: v1 kind: ConfigMap metadata: name: pg-config data: PGDATA: /var/lib/postgresql/data/pgdata POSTGRES_USER: postgres
Create the ConfigMap and the Postgres deployment:
kubectl apply -f pg-cfg.yaml
kubectl apply -f pg-deployment.yaml
If you get an error, it may be that Kubernetes has not yet started in your environment. Wait for
kubectl get nodes to show you that there is a node in
Ready state - it could take a minute or two.
Initialize the database
As a one-off exercise you need to initialize the Postgres database. To do this you will "exec in" to the postgres container in the pod - if you like, you can think of this as like SSH-ing into the container.
Check that there is a postgres pod running:
kubectl get pods
Find the ID of the postgres pod.
export pod=$(kubectl get pods -l app=postgres --no-headers -o custom-columns=":metadata.name")
kubectl exec -it $pod sh
You are now in a shell in the Postgres container. For the purposes of this demonstration you're going to manually create the database called "hello" that your Go app is going to use:
createdb -U postgres hello
And still inside the Postgres container you can manually create a "hits" table inside this database.
psql -U postgres
Connect to the hello database:
Create and initialize the hits table in this database:
CREATE TABLE hits (total int);
INSERT INTO hits (total) VALUES (0);
Quit out of
psql and out of the container.
Postgres is running in a container in a pod, and that pod has an IP address which you can see if you get the details for it with
kubectl describe pods -l app=postgres
This IP address is dynamically allocated each time a pod is created. When you write your web application, it is going to need to connect to the database pod, but it won't know the IP address. Instead, we will create a service, and the application can refer to the service by name.
apiVersion: v1 kind: Service metadata: name: postgres-svc spec: type: NodePort ports: - port: 5432 selector: app: postgres
Create this service:
kubectl apply -f pg-svc.yaml
See everything that is up and running with
kubectl get all
In fact, this is just showing you everything that is running in the default namespace. Namespaces are a way of group resources together - for example, some organizations use namespaces to separate the resources that apply to different applications, or that are owned by different teams. You'll see another namespace shortly.
You now have a Kubernetes service running Postgres. In the next step you will write a Go application that will use it.