This document gives an example of how to deploy an application in a user cluster for Google Distributed Cloud.
Before you begin
For the example given here, you need a user cluster that uses bundled MetalLB load balancing. For instructions on creating a minimal user cluster that uses MetalLB, see Create basic clusters.
Console
In the console, go to the Google Kubernetes Engine clusters overview page.
In the list of clusters, click your user cluster, and verify that you are logged in to the cluster.
If you aren't already logged in to your user cluster, log in by following the instructions in Manage clusters from the Google Cloud console.
Containers
Under New container, select Existing container image.
For Image path, enter
us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0
.Click Continue.
Configuration
For Deployment name, enter
my-deployment
.For Namespace, enter
default
.Enter these two labels:
- Key 1:
app
, Value 1:metrics
- Key 2:
department
, Value 2sales
- Key 1:
In the Kubernetes cluster drop-down, select your cluster.
Click Continue.
Expose
Check Expose deployment as a new service.
For Port 1, enter
80
.For Target port 1, enter
8080
. This is the appropriate value because thehello-app
container listens on TCP port 8080 by default. You can see this by looking at the Dockerfile and the source code for the app.For Protocol 1, select
TCP
.For Service type, select
LoadBalancer
.
At the bottom of the page, click the Deploy button.
View Deployment and Service details
When your Deployment is ready, the Deployment details page opens in the Kubernetes workloads section of the Google Cloud console. On this page, you can see details about the Deployment and its three Pods.
Under Exposing services, click the name of the Service that exposes your Deployment. For this exercise, the name is
my-deployment-service
.The Service details page opens. On this page, you can see details about Service. For example, you can see that any Pod that has the labels
app: metrics
anddepartment: sales
is a member of the Service. Recall that the Pods inmy-deployment
have these labels.
You can also see a value for Load balancer IP. The load balancer IP has been automatically configured on the cluster load balancer.
Forwarding for the Service
Suppose a client outside the cluster sends a request to the load balancer IP
on TCP port 80. The request gets routed to the cluster load balancer. The load
balancer forwards the request to a member Pod on TCP port 8080. Recall that
every Pod in my-deployment
has a container listening on TCP port 8080.
Test your Service
Go to a machine where the load balancer IP is routable.
To call your Service, enter the load balancer IP in a browser, or use a
command like curl
. For example:
curl [LOAD_BALANCER_IP]:80
The output shows a Hello, world!
message. For example:
curl 203.0.113.1:80 Hello, world! Version: 2.0.0 Hostname: my-deployment-dbd86c8c4-9wpbv
Delete the Deployment
Go to the Workloads page in the Kubernetes Engine section of the console.
In the list of Deployments, select my-deployment
.
At the top of the page, click
Delete. This deletes both the Deployment and the exposing Service.Command line
Connect to your admin workstation
Get an SSH connection to your admin workstation. Do the following steps on your admin workstation.
Create a Deployment
Here is a manifest for a Deployment:
apiVersion: apps/v1 kind: Deployment metadata: name: my-deployment spec: selector: matchLabels: app: metrics department: sales replicas: 3 template: metadata: labels: app: metrics department: sales spec: containers: - name: hello image: "us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0"
Copy the manifest to a file named my-deployment.yaml
, and create the
Deployment:
kubectl apply --kubeconfig USER_CLUSTER_KUBECONFIG -f my-deployment.yaml
where USER_CLUSTER_KUBECONFIG is the path of the kubeconfig file for your user cluster.
Get basic information about your Deployment:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG get deployment my-deployment
The output shows that the Deployment has three Pods that are all available:
NAME READY UP-TO-DATE AVAILABLE AGE my-deployment 3/3 3 3 27s
List the Pods in your Deployment:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG get pods
The output shows that your Deployment has three running Pods:
NAME READY STATUS RESTARTS AGE my-deployment-54944c8d55-4srm2 1/1 Running 0 6s my-deployment-54944c8d55-7z5nn 1/1 Running 0 6s my-deployment-54944c8d55-j62n9 1/1 Running 0 6s
Get detailed information about your Deployment:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG get deployment my-deployment --output yaml
The output shows details about the Deployment spec and status:
kind: Deployment metadata: ... generation: 1 name: my-deployment namespace: default ... spec: ... replicas: 3 revisionHistoryLimit: 10 selector: matchLabels: app: metrics department: sales ... spec: containers: - image: us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0 imagePullPolicy: IfNotPresent name: hello resources: {} terminationMessagePath: /dev/termination-log terminationMessagePolicy: File dnsPolicy: ClusterFirst restartPolicy: Always schedulerName: default-scheduler securityContext: {} terminationGracePeriodSeconds: 30 status: availableReplicas: 3 conditions: ‑ lastTransitionTime: "2019-11-11T18:44:02Z" lastUpdateTime: "2019-11-11T18:44:02Z" message: Deployment has minimum availability. reason: MinimumReplicasAvailable status: "True" type: Available ‑ lastTransitionTime: "2019-11-11T18:43:58Z" lastUpdateTime: "2019-11-11T18:44:02Z" message: ReplicaSet "my-deployment-54944c8d55" has successfully progressed. reason: NewReplicaSetAvailable status: "True" type: Progressing observedGeneration: 1 readyReplicas: 3 replicas: 3 updatedReplicas: 3
Describe your Deployment:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG describe deployment my-deployment
The output shows nicely formatted details about the Deployment, including the associated ReplicaSet:
Name: my-deployment Namespace: default CreationTimestamp: Mon, 11 Nov 2019 10:43:58 -0800 Labels:... Selector: app=metrics,department=sales Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 25% max unavailable, 25% max surge Pod Template: Labels: app=metrics department=sales Containers: hello: Image: us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0 Port: Host Port: Environment: Mounts: Volumes: Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True NewReplicaSetAvailable OldReplicaSets: NewReplicaSet: my-deployment-54944c8d55 (3/3 replicas created)
Create a Service of type LoadBalancer
One way to expose your Deployment to clients outside your cluster is to create
a Kubernetes Service of type
LoadBalancer
.
Here's a manifest for a Service of type LoadBalancer
:
apiVersion: v1 kind: Service metadata: name: my-service spec: selector: app: metrics department: sales type: LoadBalancer ports: ‑ port: 80 targetPort: 8080
For the purpose of this exercise, these are the important things to understand about the Service:
Any Pod that has the label
app: metrics
and the labeldepartment: sales
is a member of the Service. Note that the Pods inmy-deployment
have these labels.When a client sends a request to the Service on TCP port 80, the request is forwarded to a member Pod on TCP port 8080.
Every member Pod must have a container that is listening on TCP port 8080.
It happens that by default, the hello-app
container listens on TCP port
8080. You can see this by looking at the
Dockerfile and the source code
for the app.
Save the manifest to a file named my-service.yaml
, and create the Service:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG apply -f my-service.yaml
where USER_CLUSTER_KUBECONFIG is the path of the kubeconfig file for your user cluster.
When you create the Service, Google Distributed Cloud automatically
configures the loadBalancerIP
address on the cluster load balancer.
View your Service:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG get service my-service --output yaml
The output is similar to this:
kind: Service metadata: ... name: my-service namespace: default ... spec: allocateLoadBalancerNodePorts: true clusterIP: 10.96.1.39 clusterIPs: - 10.96.1.39 externalTrafficPolicy: Cluster internalTrafficPolicy: Cluster ipFamilies: - IPv4 ipFamilyPolicy: SingleStack ports: - nodePort: 31184 port: 80 protocol: TCP targetPort: 8080 selector: app: metrics department: sales sessionAffinity: None type: LoadBalancer status: loadBalancer: ingress: - ip: 203.0.113.1
In the preceding output, you can see that your Service has a clusterIP
, and
a loadBalancerIP
. It also has a port
, and a targetPort
.
The clusterIP
is not relevant to this exercise. The loadBalancerIP
is the
IP address that clients outside the cluster can use to call the Service.
As an example, take the values shown in the preceding output. That is, suppose
your Service has loadBalancerIP
= 203.0.113.1, port
= 80, and
targetPort
= 8080.
A client sends a request to 203.0.113.1 on TCP port 80. The request gets routed to the cluster load balancer. The load balancer forwards the request to a member Pod on TCP port 8080.
Call your Service:
curl LOAD_BALANCER_IP
The output shows a Hello, world!
message:
curl 203.0.113.1 Hello, world! Version: 2.0.0 Hostname: my-deployment-dbd86c8c4-9wpbv
Delete your Service
Delete your Service:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG delete service my-service
Verify that your Service has been deleted:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG get services
The output no longer shows my-service
.
Delete your Deployment
Delete your Deployment:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG delete deployment my-deployment
Verify that your Deployment has been deleted:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG get deployments
The output no longer shows my-deployment
.
What's next
Create a Service and an Ingress