9. Cloud Foundry

First, follow the instructions in the section Chapter 16, Installing on Cloud Foundry to deploy the Skipper Server to Cloud Foundry.

When you start the Skipper shell, by default, it tries to look for the Skipper server on the same (local) machine. To specify the Skipper server that is running on Cloud Foundry, provide the serverUrl when launching the shell or use the config command after the shell has started. The following example provides the serverUrl:

java -jar spring-cloud-skipper-shell-1.0.2.RELEASE.jar --spring.cloud.skipper.client.serverUri=https://mlp-skipper.cfapps.io/api

The following example uses config:

skipper:>skipper config --uri https://mlp-skipper.cfapps.io/api
Successfully targeted https://mlp-skipper.cfapps.io/api

The repo list command shows the experimental and local repositories, since they are configured by default. The local repository is where you can upload new packages. The experimental repository has a few "hello world" applications to help get you started. The following example shows the repo list command and the output of our example:

skipper:>repo list
╔════════════╤═══════════════════════════════════════════════════════════╤═════╤═════╗
║    Name    │                            URL                            │Local│Order║
╠════════════╪═══════════════════════════════════════════════════════════╪═════╪═════╣
║experimental│http://skipper-repository.cfapps.io/repository/experimental│false│0    ║
║local       │http://d4d6d1b6-c7e5-4226-69ec-01d4:7577                   │true │1    ║
╚════════════╧═══════════════════════════════════════════════════════════╧═════╧═════╝

The following example shows the package search command and the output of our example:

skipper:>package search
╔═════════════════╤═══════╤════════════════════════════════════════════════════════════════════════════════╗
║      Name       │Version│                                  Description                                   ║
╠═════════════════╪═══════╪════════════════════════════════════════════════════════════════════════════════╣
║helloworld       │1.0.1  │The app has two endpoints, /about and /greeting in Portuguese.  Maven resource. ║
║helloworld       │1.0.0  │The app has two endpoints, /about and /greeting in English.  Maven resource.    ║
║helloworld-docker│1.0.1  │The app has two endpoints, /about and /greeting in Portuguese.  Docker resource.║
║helloworld-docker│1.0.0  │The app has two endpoints, /about and /greeting in English.  Docker resource.   ║
╚═════════════════╧═══════╧════════════════════════════════════════════════════════════════════════════════╝

The command platform list shows the platforms with which the server has been configured, as shown (with its output) in the following example:

╔════╤════════════╤═════════════════════════════════════════════════════════════════════════╗
║Name│    Type    │                               Description                               ║
╠════╪════════════╪═════════════════════════════════════════════════════════════════════════╣
║pws │cloudfoundry│org = [scdf-ci], space = [space-mark], url = [https://api.run.pivotal.io]║
╚════╧════════════╧═════════════════════════════════════════════════════════════════════════╝

In the preceding example, there is only one Cloud Foundry platform. Disabling the local platform during the installation process (by setting the enableLocalPlatform property to false) caused the default local platform to not appear.

Now we can install the Hello World app (specifically, the maven based artifact). The following example shows the package install command (with its output) that we use to install the Hello World application:

skipper:>package install --release-name helloworldpcf --package-name helloworld --package-version 1.0.0 --platform-name pws --properties spec.deploymentProperties.spring.cloud.deployer.cloudfoundry.route=helloworldpcf.cfapps.io
Released helloworldpcf. Now at version v1.

The spring.cloud.deployer.cloudfoundry.route=helloworldpcf.cfapps.io deployment property is set so that, when different versions of this application are deployed, they have the same HTTP route.

Because the default value of that shell option is default`he `--platform-name pws, we used the command option. When installing Skipper, you can register a platform under the name default, but it is a best practice to specify the target platform name.

You can monitor the progress of the deployment by using the release status command, as shown (with its output) in the following example:

skipper:>release status --release-name helloworldpcf
╔═══════════════╤════════════════════════════════════════════════╗
║Last Deployed  │Thu Jan 18 13:18:44 EST 2018                    ║
║Status         │DEPLOYED                                        ║
║Platform Status│The applications are being deployed.            ║
║               │[helloworldpcf-helloworld-v1], State = [partial]║
╚═══════════════╧════════════════════════════════════════════════╝

Eventually, the Platform Status says, All applications have been successfully deployed.

[Note]Note

The DEPLOYED status in the preceding example indicates that Skipper has told the platform to deploy. Skipper does not keep track of the intermediate states 'deploying' or 'deleting'. The platform status provides finer-grained status information.

The cf apps command now has a new listing for this deployed application, as shown (with its output) in the following example:

$ cf apps
Getting apps in org scdf-ci / space space-mark as [email protected]...
OK

name                          requested state   instances   memory   disk   urls
helloworldpcf-helloworld-v1   started           1/1         1G       1G     helloworldpcf.cfapps.io

You can now curl the greeting endpoint and the about endpoint, as shown in the following example:

$ curl http://helloworldpcf.cfapps.io/greeting
Hello World!
$ curl http://helloworldpcf.cfapps.io/about
Hello World v1.0.0.RELEASE

The name of the application is based on the <release-name>-<package-name>-v<incrementing-counter> convention.

Also note that we specified a route for this application that is different than the application’s name. The deployment property spring.cloud.deployer.cloudfoundry.route is set to something that does not change across the deployment of different versions of this application — in this case, helloworldpcf.cfapps.io.

The package provides a means to template the application version, application properties, and deployment properties that are used to deploy the application to Cloud Foundry. The manifest get command shows the final YAML file which is passed off to the Spring Cloud Deployer Library, as shown (with its output) in the following example:

skipper:>manifest get --release-name helloworldpcf

---
# Source: helloworld.yml
apiVersion: skipper.spring.io/v1
kind: SpringCloudDeployerApplication
metadata:
  name: helloworld
  type: demo
spec:
  resource: maven://org.springframework.cloud.samples:spring-cloud-skipper-samples-helloworld:1.0.0.RELEASE
  applicationProperties:
  deploymentProperties:
    spring.cloud.deployer.cloudfoundry.route: helloworldpcf.cfapps.io

The manifest format is inspired by the Kubernetes Resource file format. By looking at the manifest, you can see which Maven artifact was used and which properties were set before the final push to Cloud Foundry. A future release of Skipper will use the metadata values to support searching for releases based on those values.

Since it is somewhat awkward to specify multiple flattened-out YAML values for the --properties argument in the shell, you can also specify the location of a YAML file when installing or upgrading. In the next example, we use a YAML file, named helloworld-upgrade.yml, to update the release. This application contains a Spring Boot @ConfigurationProperty named helloworld.greeting, so we set that, along with a standard Spring Boot property: endpoints.sensitive=false. We also bump the memory up to 2G from the default 1G. The contents of the helloworld-upgrade.yml file follows:

spec:
  applicationProperties:
    endpoints.sensitive: false
    helloworld.greeting: yo
  deploymentProperties:
    spring.cloud.deployer.cloudfoundry.route: helloworldpcf.cfapps.io
    spring.cloud.deployer.memory: 2048m

Now you can run the release upgrade command, as shown (with its output) in the following example:

skipper:>release upgrade --release-name helloworldpcf --package-name helloworld --package-version 1.0.0 --file /home/mpollack/helloworld-upgrade.yml
helloworldpcf has been upgraded.  Now at version v2.

The preceding example starts another instance of the hello world application, and Skipper determines when it can stop the instance of the previous instance. If you do not specify --package-version, it picks the latest version of the helloworld package. You do not need to specify the --platform-name, as it is always where the current application was deployed.

The following example shows the cf apps command and its output:

$ cf apps
Getting apps in org scdf-ci / space space-mark as [email protected]...
OK

name                          requested state   instances   memory   disk   urls
helloworldpcf-helloworld-v1   started           1/1         1G       1G     helloworldpcf.cfapps.io
helloworldpcf-helloworld-v2   stopped           0/1         2G       1G     helloworldpcf.cfapps.io

The following example shows the cf routes command and its output:

$ cf routes
Getting routes for org scdf-ci / space space-mark as [email protected] ...

space        host                          domain      port   path   type   apps                                                      service
space-mark   helloworldpcf                 cfapps.io                        helloworldpcf-helloworld-v1,helloworldpcf-helloworld-v2

At this point, Skipper is checking the health of the new application. The default health checks whether the HTTP port of the application is open. There is a customization in Skipper that influences the way the health check is performed. The spring.cloud.skipper.server.strategies.healthcheck.timeoutInMillis property is the maximum time the upgrade process waits for a healthy app. The default value is 5 minutes. Skipper fails the deployment if it is not healthy within that time. The spring.cloud.skipper.server.strategies.healthcheck.sleepInMillis property is how long to sleep between health checks.

The current upgrade strategy is very simple: If the new app is healthy, the old app is removed. There is not a rolling upgrade option, all new apps are deployed, checked for health, and then previous versions removed. More flexible upgrade strategies are planned in a future release.

You can now curl the greeting endpoint and the about endpoint, as shown in the following example:

$ curl http://helloworldpcf.cfapps.io/greeting
yo
$ curl http://helloworldpcf.cfapps.io/about
Hello World v1.0.0.RELEASE

The release list command shows the current DEPLOYED and DELETED releases for every release name. In the following example from the sample application, there is only one entry, as shown in the following example:

╔═════════════╤═══════╤══════════════════╤════════╤═══════════╤═══════════╤══════════╤════════════════════════════════════════╗
║    Name     │Version│   Last updated   │ Status │  Package  │  Package  │ Platform │         Platform Status                ║
║             │       │                  │        │   Name    │  Version  │   Name   │                                        ║
╠═════════════╪═══════╪══════════════════╪════════╪═══════════╪═══════════╪══════════╪════════════════════════════════════════╣
║helloworldpcf│2      │Thu Jan 18        │DEPLOYED│helloworld │1.0.0      │pws       │[helloworldpcf-helloworld-v2], State =  ║
║             │       │13:26:50 EST 2018 │        │           │           │          │[helloworldpcf-helloworld-v2-0=deployed]║
╚═════════════╧═══════╧══════════════════╧════════╧═══════════╧═══════════╧══════════╧════════════════════════════════════════╝

You can get the full history of the release byusing the release history command, as shown (with its output) in the following example:

skipper:>release history --release-name helloworldpcf
╔═══════╤════════════════════════════╤════════╤════════════╤═══════════════╤════════════════╗
║Version│        Last updated        │ Status │Package Name│Package Version│  Description   ║
╠═══════╪════════════════════════════╪════════╪════════════╪═══════════════╪════════════════╣
║2      │Thu Jan 18 13:26:50 EST 2018│DEPLOYED│helloworld  │1.0.0          │Upgrade complete║
║1      │Thu Jan 18 13:18:44 EST 2018│DELETED │helloworld  │1.0.0          │Delete complete ║
╚═══════╧════════════════════════════╧════════╧════════════╧═══════════════╧════════════════╝

A more typical upgrade process is not to change application properties but to change the version of the application because the code has changed. In the following example, we now upgrade the release to use a new Maven artifact, version 1.0.1, which also corresponds to version 1.0.1 of the helloworld Skipper package. In this case, we do not add any additional properties other than the route. The following example shows the release upgrade command (with its update) to deploy version 1.0.1:

skipper:>release upgrade --release-name helloworldpcf --package-name helloworld --package-version 1.0.1 --properties spec.deploymentProperties.spring.cloud.deployer.cloudfoundry.route=helloworldpcf.cfapps.io
helloworldpcf has been upgraded.  Now at version v3.

Note that the current release’s property values, such as using 2G or the greeting being yo are not carried over. A future release will introduce a --reuse-properties command that will carry the current release properties over to the next release to be made. You can monitor the status of the upgrade by using the status command, as shown (with its output) in the following example:

skipper:>release status --release-name helloworldpcf
╔═══════════════╤════════════════════════════════════════════════╗
║Last Deployed  │Thu Jan 18 13:49:42 EST 2018                    ║
║Status         │UNKNOWN                                         ║
║Platform Status│The applications are being deployed.            ║
║               │[helloworldpcf-helloworld-v3], State = [partial]║
╚═══════════════╧════════════════════════════════════════════════╝

Now a curl command shows the following output:

curl http://helloworldpcf.cfapps.io/greeting
Olá Mundo!
$ curl http://helloworldpcf.cfapps.io/about
Hello World v1.0.1.RELEASE

Our release history is now as follows:

skipper:>release history --release-name helloworldpcf
╔═══════╤════════════════════════════╤════════╤════════════╤═══════════════╤════════════════╗
║Version│        Last updated        │ Status │Package Name│Package Version│  Description   ║
╠═══════╪════════════════════════════╪════════╪════════════╪═══════════════╪════════════════╣
║3      │Thu Jan 18 13:49:42 EST 2018│DEPLOYED│helloworld  │1.0.1          │Upgrade complete║
║2      │Thu Jan 18 13:26:50 EST 2018│DELETED │helloworld  │1.0.0          │Delete complete ║
║1      │Thu Jan 18 13:18:44 EST 2018│DELETED │helloworld  │1.0.0          │Delete complete ║
╚═══════╧════════════════════════════╧════════╧════════════╧═══════════════╧════════════════╝

Next, we use the rollback command to deploy an older version of the application. Since we have the manifest for that version, we have all we need to redeploy an earlier release. The following example shows the release rollback command and its output:

skipper:>release rollback --release-name helloworldpcf --release-version 2
helloworldpcf has been rolled back.  Now at version v4.

The history now shows a new v4 version, even though it is identical in terms of app behavior to the v2 version, as follows:

skipper:>release history --release-name helloworldpcf
╔═══════╤════════════════════════════╤════════╤════════════╤═══════════════╤════════════════╗
║Version│        Last updated        │ Status │Package Name│Package Version│  Description   ║
╠═══════╪════════════════════════════╪════════╪════════════╪═══════════════╪════════════════╣
║4      │Thu Jan 18 13:51:43 EST 2018│DEPLOYED│helloworld  │1.0.0          │Upgrade complete║
║3      │Thu Jan 18 13:49:42 EST 2018│DELETED │helloworld  │1.0.1          │Delete complete ║
║2      │Thu Jan 18 13:26:50 EST 2018│DELETED │helloworld  │1.0.0          │Delete complete ║
║1      │Thu Jan 18 13:18:44 EST 2018│DELETED │helloworld  │1.0.0          │Delete complete ║
╚═══════╧════════════════════════════╧════════╧════════════╧═══════════════╧════════════════╝

The curl commands shows the following output:

$ curl http://helloworldpcf.cfapps.io/greeting
yo
$ curl http://helloworldpcf.cfapps.io/about
Hello World v1.0.0.RELEASE