Version 1.6. This version is supported as outlined in the Anthos version support policy, offering the latest patches and updates for security vulnerabilities, exposures, and issues impacting Anthos clusters on VMware (GKE on-prem). Refer to the release notes for more details. This is not the most recent version.

Deploying an application

This document shows how to deploy an application in your user cluster for Anthos clusters on VMware (GKE on-prem).

Before you begin

Create a user cluster (quickstart | full instructions).

SSH into your admin workstation

SSH into your admin workstation:

ssh -i ~/.ssh/vsphere_workstation ubuntu@[IP_ADDRESS]

where [IP_ADDRESS] is the IP address of your admin workstation.

Do all of the remaining steps in this topic on your admin workstation.

Creating 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: "gcr.io/google-samples/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: gcr.io/google-samples/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:        gcr.io/google-samples/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)

Creating 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
  loadBalancerIP: [SERVICE_IP_ADDRESS]
  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 label department: sales is a member of the Service. Note that the Pods in my-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.

Replace [SERVICE_IP_ADDRESS] with an address that you own that is not already in use. For example, you could set this to a public IP address that your company owns. Or you could set it to a private address in your company network.

The address you choose must be routable from the location of any client that sends requests to the Service. For example, if you choose a private address, then external clients will not be able to send requests to the Service.

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 your user cluster's kubeconfig file.

When you create the Service, Anthos clusters on VMware automatically configures the loadBalancerIP address on your F5 BIG-IP load balancer.

View your Service:

kubectl --kubeconfig [USER_CLUSTER_KUBECONFIG] get service my-service --output yaml

The output is similar to this:

apiVersion: v1
kind: Service
metadata:
  ...
  name: my-service
  namespace: default
  ...
spec:
  clusterIP: 10.107.84.202
  externalTrafficPolicy: Cluster
  loadBalancerIP: 203.0.113.1
  ports:
  - nodePort: 31919
    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 nodePort, a port, and a targetPort.

The clusterIP is not relevant to this exercise. The loadBalancerIP is the IP address that you provided in my-service.yaml.

As an example, take the values shown in the preceding output. That is, suppose your Service has loadBalancerIP = 203.0.113.1, port = 80, nodePort = 31919, and targetPort = 8080.

A client sends a request to 203.0.113.1 on TCP port 80. The request gets routed to your F5 BIG-IP load balancer. The load balancer chooses one of your user cluster nodes, and forwards the request to [NODE_ADDRESS] on TCP port 31919. The iptables rules on the node forward the request to a member Pod on TCP port 8080.

Call your Service:

curl [SERVICE_IP_ADDRESS]

where [SERVICE_IP_ADDRESS] is the address that you specified for loadBalancerIP.

The output shows a Hello, world! message:

curl 21.0.133.48
Hello, world!
Version: 2.0.0
Hostname: my-deployment-dbd86c8c4-9wpbv

Deleting 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.

Deleting 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

Enabling ingress