Deploying apps
Deploying public apps
By default, all apps you deploy on Cloud Foundry are publicly accessible to everyone through the internet.
The cf push
command can both create a new app and push a new version of an existing app.
Put your app’s code and configuration files in a local directory.
Target the appropriate organisation and space by running:
cf target -o ORG_NAME -s SPACE_NAME
where
ORG_NAME
is the name of the org, andSPACE_NAME
is the name of the space.Create a
manifest.yml
file in the same local directory as your app’s code. The manifest file tells Cloud Foundry what to do with your app. An example manifest:--- applications: - name: APP_NAME
where
APP_NAME
is the unique name for your app. You can runcf apps
to see apps which already exist.Deploy your app by running the following in the directory which contains your app’s code, configuration files, and manifest:
cf push
Your app should now be live at your app domain.
Refer to the Cloud Foundry documentation on Deploying with Application Manifests [external link] for more information on the options available when you deploy an app.
Refer to the production checklist if your app is a production app.
Set a target
To deploy an app, you need to set a target. A target is a combination of an org and a space.
Run the following to set the target:
cf target -o ORG_NAME -s SPACE_NAME
where ORG_NAME
is the name of the org, and SPACE_NAME
is the name of the space.
The Cloud Foundry client remembers the target until you change it.
You can change space without changing org by running:
cf target -s SPACE_NAME
You should target the sandbox space while you are testing your app. You can do this by running:
cf target -s sandbox
You will not normally need to target the sandbox space if you are a new user, as this space is the default for new users.
A possible exception to this is if your org is mature and has pre-existing spaces; you should check to ensure that you target the appropriate space for testing.
Caveats
- Your app should not write to local storage. Cloud Foundry local storage is ephemeral and can be deleted at any time.
- You may need to set environment variables for your app to work. All configuration information should be stored in environment variables, not in the code.
- Instances will be restarted if they exceed memory limits.
- Your application should write all its log messages to
STDOUT
/STDERR
, rather than a log file.
Deploying private apps
You can deploy apps so they are not publicly accessible to everyone through the internet.
The simplest use case is that you have 2 apps to deploy:
- a public app for your end users to interact with
- a private app that the public app can securely connect to, but which is not accessible from the internet
To achieve this, you must:
- specify the private route in the private app’s manifest
- set the private app URL as an environment variable in the public app’s manifest
- create a network policy to allow the apps to connect with each other
If you need to restrict access to a public app, you should refer to the documentation on route services.
Specify a private route in the private app’s manifest
Cloud Foundry uses routes [external link] to send requests to apps.
You must specify a private route in the private app’s manifest to tell Cloud Foundry that this app should not be accessible from the internet.
Create the private app’s manifest.yml
with the following code:
---
applications:
- name: PRIVATE_APPNAME
routes:
- route: PRIVATE_APPNAME.apps.internal
If the private app was previously a public app, you must also run the following in the command line to remove the pre-existing public route:
cf unmap-route PRIVATE_APPNAME DOMAIN --hostname HOSTNAME
Set the private app URL in the public app’s manifest
The public app must read the private app URL from an environment variable in the public app’s manifest.
Connections between public and private apps are not encrypted by default.
If you need encrypted connections between your apps, it is your responsibility to implement this.
You must set:
- the private app URL as a non-secure
http
URL - the domain as
apps.internal
- the URL as port
8080
To do this, create the public app’s manifest.yml
with the following code:
---
applications:
- name: PUBLIC_APPNAME
env:
ENVIRONMENT_VARIABLE_NAME: http://PRIVATE_APPNAME.apps.internal:8080
where:
PUBLIC_APPNAME
is the name of your public appENVIRONMENT_VARIABLE_NAME
is the environment variable your public app reads (for examplePRIVATE_APP_URL
)PRIVATE_APPNAME
is the name of your private app
Create a network policy
By default, Cloud Foundry apps do not accept internal connections from other apps.
You must create a network policy [external link] to allow the public app to connect to the private app.
- Push both the public and private apps.
- Run the following in the command line to create the network policy:
cf add-network-policy PUBLIC_APPNAME --destination-app PRIVATE_APPNAME --protocol tcp --port 8080
Contact us at gov-uk-paas-support@digital.cabinet-office.gov.uk if you have any further questions.
Data security classification
You can store data classified up to ‘official’ on the GOV.UK PaaS.
You cannot store data classified ‘secret‘ or ‘top secret‘ on the GOV.UK PaaS.
Refer to the information assurance page for information on the assurance process.
Refer to the GOV.UK page on government security classifications for more information on these classifications.
Secure and non-secure requests
Requests could be made to an app’s public route over the non-secure http://
protocol due to:
- misconfiguration of an app that allows non-encrypted traffic through
- a service linking to the HTTP version of a page by mistake
Any requests made to a public app route over the http://
protocol will be automatically redirected to the base https://
version of that URL. The original query path and query parameters will be removed. This prevents a site from repeatedly redirecting back to the HTTP protocol without the user noticing.
Buildpacks
About buildpacks
Cloud Foundry uses buildpacks to provide runtime and framework support for applications in different languages (for example ensuring your app code has both the Ruby runtime and the Rails framework available to help it run). GOV.UK PaaS supports both standard and custom buildpacks:
- standard buildpacks [external link] are buildpacks for common languages and frameworks that are supported by Cloud Foundry. You can check the installed buildpacks and their versions by running
cf buildpacks
. - custom buildpacks are developed by the wider community to enable hosting of applications in additional languages or frameworks
- Docker images are a packaging format, and the requirements for the app and its runtime environment are the same as for apps deployed using buildpacks
Which buildpack should I use?
We recommend using the standard buildpacks to maximise the support you will receive from GOV.UK PaaS. Using a custom buildpack or Docker image will mean additional setup and maintenance costs.
Your responsibilities change depending on whether you use a standard buildpack, custom buildpack or a Docker image. Refer to the responsibility model guidance for further information.
Buildpack language version updates
You should tell Cloud Foundry which version of your app’s language to use in the buildpack. You can specify an exact, minor or major version of the language. For example, with Python:
Category | Python Example |
---|---|
Exact | 3.5.2 |
Minor | 3.5.x |
Major | 3.x |
If you specify an exact version, you must update this version when the GOV.UK PaaS team update the language’s buildpack. Your app will fail to start if the language version it relies on is not supported by the latest language buildpack.
If you specify a major or a minor version, your app will automatically upgrade to use a more recent version of its language when the GOV.UK PaaS team updates the buildpack. The major or minor version must still be live for this upgrade to work. However, if there is a breaking change between language versions, your app may not behave as expected or even fail.
You should always check the GOV.UK PaaS announcements email for information on which language versions are in the latest language buildpacks.
How to use custom buildpacks
There are many application attribute options available when you push an app. You can use the buildpack attribute to specify a custom buildpack for your app through:
- specifying the buildpack in the manifest.yml file
- using the command line
Specifying buildpacks in the manifest file
You can set application attribute options in a manifest.yml file in the directory from which you are running the push command. This is done in one of three ways:
- By name: MY-BUILDPACK.
- By GitHub URL: https://github.com/cloudfoundry/java-buildpack.git.
- By GitHub URL with a branch or tag: https://github.com/cloudfoundry/java-buildpack.git#v3.3.0 for the v3.3.0 tag.
---
...
buildpack: buildpack_URL
Command line options override the manifest; the option that overrides the custom buildpack attribute is
-b
.
Using the command line to choose buildpacks
Once a custom buildpack has been created, it can be pushed to either a public or private git repository. The repository URL can then be included in the command line to push your app.
If the repository is private, the push command must include https and username/password authentication
- Public:
$ cf push my-new-app -b git://github.com/johndoe/my-buildpack.git
- Private:
$ cf push my-new-app -b https://username:password@github.com/johndoe/my-buildpack.git
The app will then be deployed to Cloud Foundry, and the buildpack will be cloned from the repository and applied to the app.
If a buildpack is specified using
cf push -b
the detect step will be skipped and as a result, no buildpack detect scripts will be run.
Excluding files
Cloud Foundry isn’t version-control-aware, so cf push
will deploy the working state of whatever files you have in that directory. In most cases, you will want to exclude files [external link] ignored by Git. From within your project directory, run
ln -s .gitignore .cfignore
and commit the .cfignore
to your repository. However, read on if you have a more advanced CF setup.
A couple of important points on the .cfignore
:
if you have a more advanced app setup and have apps with a
path
other than the project root (where you runcf push
from), you will need an additional.cfignore
file located in each apppath
;also note that more advanced
.gitignore
syntax, such as the**
recursive subdirectory wildcard, are not supported by.cfignore
.
Environment variables
You must store all configuration information for your app as environment variables.
This could include:
- credentials for external services that your app uses, for example a Twitter account
- values that will vary with each deployment of the app, for example the canonical URL
To view an app’s current environment variables, run cf env APP_NAME
.
To create or update a variable, run the following:
cf set-env APP_NAME ENV_VAR_NAME ENV_VAR_VALUE
If you’re deploying a pre-existing app, you should check the app’s documentation for any environment variables you need to set.
For example, if the app has these instructions for deploying to Heroku:
heroku config:set VARIABLE=value
then you should run the equivalent command using cf set-env
:
cf set-env APP_NAME VARIABLE value
System-provided environment variables
System-provided environment variables tell you about configuration details handled by the PaaS, for example:
- the port on which the app is listening
- the maximum memory each app instance can use
- the external IP address of the app instance
Do not attempt to change the values of these system-provided variables using the command line or your app’s code.
VCAP_SERVICES
and VCAP_APPLICATION
are two important variables for initial setup:
VCAP_SERVICES
contains details, including credentials, of any backing services bound to the appVCAP_APPLICATION
provides details of the currently running application, for example the language runtime version
To see the values of the system-provided variables, run cf env APP_NAME
.
If your app connects to a backing service, you may need to have your app parse VCAP_SERVICES
to get the credentials and other settings relating to that service and set the appropriate environment variables.
Some buildpacks will do this for you automatically. Refer to the deploy instructions for the language or framework you are using for more information.
Here is an example of the structure of the information contained in VCAP_SERVICES
:
{
"VCAP_SERVICES": {
"postgres": [
{
"binding_name": null,
"credentials": {
"host": "rdsbroker-66ecd739-2e98-401a-9e45-15436165be06.c7uewwm9qebj.eu-west-1.rds.amazonaws.com",
"jdbcuri": "jdbc:postgresql://rdsbroker-66ecd739-2e98-401a-9e45-17938165be06.c7uewwm9qebj.eu-west-1.rds.amazonaws.com:5432/DATABASE_NAME?password=PASSWORD\u0026ssl=true\u0026user=USERNAME",
"name": "DATABASE_NAME",
"password": "PASSWORD",
"port": 5432,
"uri": "postgres://USERNAME:PASSWORD@rdsbroker-66ecd739-2e98-401a-9e45-17938165be06.c7uewwm9qebj.eu-west-1.rds.amazonaws.com:5432/DATABASE_NAME",
"username": "USERNAME"
},
"instance_name": "SERVICE_NAME",
"label": "postgres",
"name": "SERVICE_NAME",
"plan": "PLAN",
"provider": null,
"syslog_drain_url": null,
"tags": [
"postgres",
"relational"
],
"volume_mounts": []
}
]
}
}
Refer to the Cloud Foundry Environment Variables documentation [external link] for a full list of environment variables.
Names, routes and domains
App names and domain hostname clash
When you push an app, you have to assign an app name, either in the manifest or using the command line. The app name is also used as the default hostname of the app domain where the app will be hosted.
For example, if you push an app called myapp
in the London region, the PaaS tries to host it at myapp.london.cloudapps.digital
. This is done using Cloud Foundry’s route functions.
The app domain is shared across all PaaS tenants within a region. in this example, if another tenant is using myapp.cloudapps.digital
in the Ireland region, and you try to push an app called myapp
to the same region, you will receive an error like this:
Using route myapp.london.cloudapps.digital
Binding myapp.london.cloudapps.digital to myapp...
FAILED
The route myapp.london.cloudapps.digital is already in use.
This will also happen if there is an app with the same name within your own organisation, but in a different space.
There are a few possible solutions to this problem:
Minimise the chance of name clash by the way you name your apps; incorporate the name of your team, department or service to produce names that are unlikely to clash with other PaaS tenants. For example, if you work for the Ministry of Peace, instead of
myapp
, you could useminipeace-myapp
.If you run different versions of an app in different spaces, you will also need to name them differently: for example, you might have
minipeace-myapp-dev
,minipeace-myapp-test
,minipeace-myapp-production
and so on.Manually specify a hostname that is different from the app name. You can do this as a command line option when you push:
cf push myapp -n HOSTNAME
or with a line in the app’s
manifest.yml
file:--- ... host: HOSTNAME
You will still need to pick a hostname that is not in use.
This solution means you can change the hostname while keeping the app name the same. This is more flexible, but means you need to keep track of both a hostname and an app name for each app. It could potentially make it easier to deploy to the wrong target.
Use the
random-route
option. This appends a couple of random words to the hostname, to avoid clashes. For example, if your app is hosted in the London region and you run:cf push myapp --random-route
the app will be hosted at something like
https://myapp-mummifying-giraffe.london.cloudapps.digital
.You can also specify this in your app’s
manifest.yml
file:random-route: true
This is a convenient way to avoid clashes automatically. The disadvantage is that if your end users can see the resulting URLs, they may find the random words strange.
Custom domains
In production, you will probably want your app to be available through your own url (for example, yourapp.service.gov.uk
). Refer to managing custom domains using the cdn-route service to see how to set this up.
Deploy a static HTML page
Refer to the Deploy a test static HTML section of the documentation.
Deploy a Ruby on Rails app
This section explains minimal steps for deploying a basic Rails app. For full details of how to deploy Ruby on Rails apps, see the official Cloud Foundry guide Getting Started Deploying Ruby on Rails Apps [external link].
If your app requires a backing service, it must be able to work with one of the services supported by PaaS. Instructions for deploying both backing service and non-backing service apps are given in this section.
These steps assume you have already carried out the setup process explained in the Get started section.
When you deploy an app, you must select a combination of an organisation and a space. This is called the target.
We have provided a sandbox
space for you to use for learning about the PaaS. You may want to target the sandbox while you are testing by running:
cf target -s sandbox
It’s also important to realise that if you deploy an app using the same name and target as an existing app, the original will be replaced. If you are not sure about where to deploy your app, consult the rest of your team.
Deploying an app
To deploy a Rails app that doesn’t require a backing service:
Put the code for your Rails app into a local directory (for example, by checking it out of version control).
If you’re using Rails 4, add the
rails_12factor
gem for better logging. Rails 5 has this functionality built in by default.Create a manifest.yml file in the folder where you checked out your app.
--- applications: - name: my-rails-app memory: 256M buildpack: ruby_buildpack
Replace
my-rails-app
with a unique name for your app. (You can usecf apps
to see apps which already exist).The
memory
line tells the PaaS how much memory to allocate to the app.A buildpack provides any framework and runtime support required by an app. In this case, because the app is written in Ruby, you use the
ruby_buildpack
.Upload and start the application by running:
cf push APPNAME
from the directory which contains all the code and configuration files for your app.
If you do not specify a name for the app after the
cf push
command, the name from the manifest file is used.Set any additional environment variables required by your app. For example:
cf set-env APPNAME VARIABLE `value`
where VARIABLE is a unique name for the variable, and
value
is the value to set.
Your app should now be available at your app domain.
For a production app, you should read the production checklist.
Deploying with a PostgreSQL database
These instructions are for deploying a Rails app with a PostgreSQL database, and can be applied to other backing services. If you require more guidance on deploying an app with other supported backing services, contact us at gov-uk-paas-support@digital.cabinet-office.gov.uk.
The Cloud Foundry buildpack for Ruby automatically gets the details of the first available PostgreSQL service from the VCAP_SERVICES
environment variable and sets the Ruby DATABASE_URL
environment variable accordingly. Ensure that your app is configured to use DATABASE_URL
to set its database configuration when deployed to the PaaS.
Put the code for your Rails app into a local directory (for example, by checking it out of version control).
If you are using Git, you may wish to exclude files ignored by Git.
If you’re using Rails 4, add the
rails_12factor
gem for better logging. Rails 5 has this functionality built in by default.Create a manifest.yml file in the directory where you checked out your app.
--- applications: - name: my-rails-app memory: 256M buildpack: ruby_buildpack
Replace
my-rails-app
with a unique name for your app. (You can usecf apps
to see apps which already exist).The
memory
line tells the PaaS how much memory to allocate to the app.A buildpack provides any framework and runtime support required by an app. In this case, because the app is written in Ruby, you use the
ruby_buildpack
.Upload the app without starting it using this command:
cf push --no-start APPNAME
from the directory which contains all the code and configuration files for your app.
If you do not specify a name for the app after the
cf push
command, the name from the manifest file is used.Set any additional environment variables required by your app. For example:
cf set-env APPNAME VARIABLE `value`
where VARIABLE is a unique name for the variable, and
value
is the value to set.Create a PostgreSQL backing service (if required) and bind it to your app.
To enable Rails support for database migrations, you may wish to create a
Procfile
in the same directory as yourmanifest.yml
andGemfile
. TheProcfile
is a way to specify commands to be run when deploying your app.This is a minimal example of the
Procfile
content for Rails 5.0:web: rake db:migrate && bin/rails server
Start your app by running:
cf start APPNAME
Your app should now be available at your app domain.
For a production app, you should read the production checklist.
Specify a Ruby version
You should tell Cloud Foundry which version of Ruby your app uses in the Ruby buildpack.
Refer to the documentation on buildpack language version updates for more information.
Refer to the Cloud Foundry documentation for more information on how to specify a Ruby version [external link].
Web servers
By default, the Cloud Foundry Ruby buildpack runs bin/rails server
to spin up the application. In Rails 4 and below, this will use WEBrick as the web
server. In Rails 5 and above, the default is
puma.
You may want to use a different web server in production. See the Cloud Foundry docs for more information on configuring a production server [external link].
Troubleshooting asset precompilation
By default, the Rails buildpack performs asset precompilation during the staging phase. This is fine for most Rails apps, but it won’t work for those which need to connect to services (such as the database) during asset compilation. (For an example, see MyUSA issue #636)
There are multiple potential solutions for this. For more advice, see the Cloud Foundry document on the subject [external link].
Deploy a Node.js app
This section covers how to deploy a basic Node.js application to GOV.UK PaaS. See the Cloud Foundry Tips for Node.js Applications [external link] for more details.
If your app requires a backing service, it must be able to work with one of the services supported by PaaS. Instructions for deploying both backing service and non-backing service apps are given in this section.
These instructions assume you have already carried out the setup process explained in the Get started section.
This is the code for the example app we are going to use. It is a basic web server that responds with a ‘Hello World’ message.
const http = require('http');
const port = process.env.PORT || 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World\n');
});
server.listen(port, () => {
console.log(`Server running on ${port}/`);
});
Save the code to a new local directory as
example.js
.Add this
manifest.yml
file to the same directory:--- applications: - name: my-node-app command: node example.js memory: 256M buildpack: nodejs_buildpack
Replace
my-node-app
with a unique name for your app. (You can usecf apps
to see apps which already exist).The
memory
line tells the PaaS how much memory to allocate to the app.A buildpack provides any framework and runtime support required by an app. In this case, because the app is written in Node.js, you use the
nodejs_buildpack
.Include an npm
package.json
file to specify dependencies. The file should also specify astart
command used to launch the app.This is a
package.json
file for our example app:{ "name": "example", "version": "0.0.1", "author": "Demo", "engines": { "node": "6.11.x" } }
The
"engines"
values specify the versions of Node.js and npm that the PaaS should use to run your app. Note that older versions may not be available: if your version is not supported, you will see an error message when you try to upload and start the app.You can optionally run
npm install
to preinstall dependencies rather than having them added during the PaaS staging process.Run
cf push APPNAME
from the top level of the directory which contains all the code and configuration files.
If you want to upload the app without starting it (for example, if you need to create a PostgreSQL service), run cf push --no-start APPNAME
, then when you are ready to start the app, run cf start APPNAME
.
See Tips for Node.js Applications [external link] in the Cloud Foundry documentation for more information.
PostgreSQL setup with Node.js
These instructions are for deploying a Node.js app with a PostgreSQL database, and can be applied to other backing services. If you require more guidance on deploying an app with other supported backing services, contact us at gov-uk-paas-support@digital.cabinet-office.gov.uk.
If your app depends on a backing service such as PostgreSQL, it will need to parse the VCAP_SERVICES
environment variable to get required details, such as service URLs and credentials.
You must create the service and bind it to your Node.js app as described in the PostgreSQL section.
You can use the cfenv module to assist with parsing the environment variables.
In your package.json
file, you would specify cfenv
as a dependency:
{
// ...
"dependencies": {
"cfenv": "*",
// ...
}
}
Then in your app, you can easily get configuration information for backing services. This is an example of how to connect to a PostgreSQL service.
var cfenv = require("cfenv");
var pg = require('pg');
var appEnv = cfenv.getAppEnv();
var connectionString = appEnv.getServiceURL("SERVICE NAME");
var client = new pg.Client(connectionString);
client.ssl = true;
client.connect();
Replace “SERVICE NAME” in the above code with the exact name of the PostgreSQL service you created. The getServiceURL
function returns a connection string which includes the username and password required to connect to the database.
Further information can be found in:
- the Cloud Foundry community
cf env
page [external link] - the Cloud Foundry documentation on environment variables [external link]
You should also remember to include dependencies for any service bindings in package.json
.
{
// ...
"dependencies": {
"pg": "*",
// ...
}
}
Specify a Node.js version
You should tell Cloud Foundry which version of Node.js your app uses in the Node.js buildpack.
Refer to the documentation on buildpack language version updates for more information.
Refer to the Cloud Foundry documentation for more information on how to specify a Node.js version [external link].
Deploy a Django app
This section explains how to deploy an app using the Django framework. You may also need to refer to the Cloud Foundry documentation about the Python buildpack [external link].
If your app requires a backing service, it must be able to work with one of the services supported by PaaS. Instructions for deploying both backing service and non-backing service apps are given in this section.
Before deploying a Django app, you must:
- log into your PaaS account
- set up the Cloud Foundry command line
- target the appropriate space
Put the code for your Django app into a local directory (for example, by checking it out of version control).
If you are using Git, add
*.pyc
andlocal_settings.py
to your.gitignore
file, then exclude files ignored by Git so Cloud Foundry will ignore them too.Run
cf buildpacks
in the command line to check the version of the Python buildpack.Go to the Python buildpack page on GitHub to check which versions of Python are currently included in the Python buildpack.
Tell Cloud Foundry which version of Python to use by creating a
runtime.txt
file in the root of the local directory. This step is optional.Refer to the documentation on buildpack language version updates for more information.
Refer to the Cloud Foundry documentation for more information on how to specify a Python version [external link].
Make sure you have all the required modules for your project installed into your virtual environment (including Django).
Generate a
requirements.txt
file if your project doesn’t already have one by runningpip freeze > requirements.txt
in the root of the local folder. Add the following lines to therequirements.txt
file.whitenoise==1.0.6 #manages static assets waitress==0.8.9 #a pure python WSGI server that is a replacement for gunicorn
Edit your
wsgi.py
file.When you create a Django project, a default
wsgi.py
file should be created for you in the project folder. Excluding the opening comments, the defaultwsgi.py
looks like this:import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "PROJECTNAME.settings") from django.core.wsgi import get_wsgi_application application = get_wsgi_application()
You’ll need to add a few lines to import the
whitenoise
package and wrap the middleware around the WSGI application so that all static files are served using whitenoise. Edit yourwsgi.py
to:import os from django.core.wsgi import get_wsgi_application os.environ.setdefault("DJANGO_SETTINGS_MODULE", "PROJECTNAME.settings") # important that the whitenoise import is after the line above from whitenoise.django import DjangoWhiteNoise application = get_wsgi_application() application = DjangoWhiteNoise(application)
The order here is important. The
DJANGO_SETTINGS_MODULE
environment variable must be set before importingDjangoWhiteNoise
.You should now tell Django where to look for static files. In
settings.py
within the project folder, add these lines below theimport os
statement.PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) STATIC_ROOT = os.path.join(PROJECT_ROOT, 'static') STATIC_URL = '/static/'
In this case, the STATIC_ROOT variable tells Django to look for static files in a directory called
static
inside the project folder, and the STATIC_URL variable sets the path where those files will be served.You may need to alter these values depending on how static files are handled in your app.
If your static files are located across multiple folders, you may need to use the STATICFILES_DIRS variable. See the Django documentation for full details on managing static files.
Create a file called
Procfile
in the root of your local folder, and put in it:web: python manage.py migrate && waitress-serve --port=$PORT PROJECTNAME.wsgi:application
The Procfile is a way to specify commands to be run when deploying your app; in this case, for database migration.
PROJECTNAME
should be replaced with whatever the name of your WSGI module is. By default, this is the same as the name of your project module, but it may be changed using the DJANGO_SETTINGS_MODULE environment variable. Using this configuration will automatically apply any database migrations.Create a
manifest.yml
file in the root of your local folder.--- applications: - name: my-app memory: 512M buildpack: python_buildpack
where
my-django-app
is the name that will be used for the app within GOV.UK PaaS.Replace
my-django-app
with a unique name for your app. (You can usecf apps
to see apps which already exist).The
memory
line tells the PaaS how much memory to allocate to the app.If your app requires a database, create a PostgreSQL backing service and bind it to your app. Then see the section on PostgreSQL setup below.
To push your app, do:
cf push APPNAME
from the directory which contains all the code and configuration files.
If you want to upload the app without starting it (for example, if you need to create a PostgreSQL service), run
cf push --no-start APPNAME
, then when you are ready to start the app, runcf start APPNAME
.
You can now view your app at your app domain.
PostgreSQL setup with Django
These instructions are for deploying a Django app with a PostgreSQL database, and can be applied to other backing services. If you require more guidance on deploying an app with other supported backing services, contact us at gov-uk-paas-support@digital.cabinet-office.gov.uk.
Add these lines to your requirements.txt
:
psycopg2==2.6.2 #installs the postgres driver
dj-database-url==0.3.0 #grabs environment variables and dumps them into a Django settings file
In your settings.py
file, make sure you import the dj_database_url
package we added to the requirements.txt
file above:
import dj_database_url
This package will automatically parse the VCAP_SERVICES
environment variable and set DATABASE_URL to the first database found.
Then you’ll need to add a DATABASES
setting. It’s best to add this to the settings.py
file.
DATABASES = {}
DATABASES['default'] = dj_database_url.config()
Your local_settings.py
file will override this when you’re working locally.
The Procfile
configuration provided in the section above will automatically apply database migrations.
Deploy a Java app
This section covers how to deploy a Java application to GOV.UK PaaS using the Java buildpack [external link].
Deploying a JAR file
If your java application can be packaged as a self-executable JAR [external link] then deployment can be as simple as using cf push -p [your-app].jar [your-app-name]
.
This example will walk through creating a simple “Hello World” application that embeds the popular (Jetty) [external link] webserver. The instructions assume you have already carried out the setup process explained in the Get started section.
Create a directory for your Java application:
mkdir myapp cd myapp
Download Jetty.
curl -o ./jetty.jar http://central.maven.org/maven2/org/eclipse/jetty/aggregate/jetty-all/9.4.6.v20170531/jetty-all-9.4.6.v20170531-uber.jar
This example uses version 9.4.6; check http://www.eclipse.org/jetty/download.html for the latest version of Jetty.
Create a
App.java
file in your application directory. This class will serve as the entry point for your application:package app; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.AbstractHandler; public class App extends AbstractHandler { @Override public void handle( String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response ) throws IOException, ServletException { response.setContentType("text/html; charset=utf-8"); response.setStatus(HttpServletResponse.SC_OK); response.getWriter().println("<h1>Hello World</h1>"); baseRequest.setHandled(true); } public static void main( String[] args ) throws Exception { int port = Integer.parseInt(System.getenv("PORT")); Server server = new Server(port); server.setHandler(new App()); server.start(); server.join(); } }
Compile your class:
javac -d . -cp ./jetty.jar App.java
Combine your class with Jetty to create an executable jar file:
jar uvfe ./jetty.jar app.App app/App.class
Push your jar file.
cf push your-app-name -b java_buildpack -p ./jetty.jar
You have now deployed your Java application. Your application should now be accessible over HTTPS from the URL provided in the output.
If your application requires arguments in order to start, you can set the JBP_CONFIG_JAVA_MAIN
environment variable. For example to add server
and config.yml
as arguments for your app, you could add the following to your application’s manifest.yml
:
env:
JBP_CONFIG_JAVA_MAIN: '{ arguments: "server config.yml" }
Deploying a WAR file
If your application can be packaged as a .war
file you can deploy with the following:
cf push your-app-name -b java_buildpack -p your-app.war
If you need to use a specific version of Tomcat you can set the environment variable JBP_CONFIG_TOMCAT
. For example to use Tomcat 8 you could add the following to your application’s manifest.yml
:
env:
JBP_CONFIG_TOMCAT: '{ tomcat: { version: 8.0.+ } }'
Note that you do not need to deploy Tomcat along with your application. The Java buildpack will run the servlet 2 and 3 web applications.
For more configuration options see Tomcat Container [external link].
Specify a Java version
You can specify the version of the Java Runtime Environment (JRE) by setting the environment variable JBP_CONFIG_OPEN_JDK_JRE
in the application’s manifest.yml
. For example, to use JRE 11:
env:
JBP_CONFIG_OPEN_JDK_JRE: '{ jre: { version: 11.+ } }'
The +
in this example means it will use the latest point release available.
Deploying other JVM-based applications
The Java buildpack supports running any JVM-based applications (such as Scala, Clojure etc.) with little or zero additional configuration. For detailed examples of deploying applications using other frameworks and JVM-based languages:
- Embedded web server [external link]
- Grails [external link]
- Groovy [external link]
- Java Main [external link]
- Play Framework [external link]
- Servlet [external link]
- Spring Boot CLI [external link]
- Cloud Foundry Java Buildpack documentation [external link]
- Cloud Foundry tips for java developers [external link] for more information.
Stopping and deleting apps
It’s important to know that when you perform a cf push
command, there are three things that happen on the platform:
- your code is uploaded, after which a buildpack converts it to a single container, called a ‘droplet’, that can be run on PaaS as an app
- the droplet is used to start the requested number of instances of that app
- a route is created, connecting your app to the internet
When deleting apps you need to remember aspects 1 and 3.
Databases, CDNs and other services have a different lifecycle and need to be removed separately.
Stopping and starting apps
If you temporarily want to stop your app, freeing up memory from your quota, you can use the command
cf stop [appname]
This will stop the app running (although databases and other provisioned services will still be running and chargeable). Users visiting your app’s URL will get the error 404 Not Found: Requested route ('[appname].[app domain]') does not exist.
You can start a stopped app with
cf start [appname]
Deleting apps
BEFORE YOU START: This is irreversible. We strongly recommend running the cf target
command before you start: check you are where you think you are, and working on what you think you are working on.
If you want to remove your app completely it’s tempting to jump in with the cf delete
command, but there are a few things to beware of:
- Services that are used by apps do not automatically get deleted, and would still be chargeable
- Routes between the internet and your apps need to be explicitly removed.
If you have a simple app without any services the best way to delete it is
cf delete -r [APPNAME]
which will delete the app and its routes in one go. If your app does have services, please delete them first.
If you accidentally delete your app without the -r
option, you can delete the route manually. First confirm the details of the orphaned route by typing the cf routes
command, to get a list of all active routes in the current space. This will list the space, the hostname, the app domain, port, path, type and any bound apps or services. You will see your hostname listed but without an associated app. Use this information to populate the following command:
cf delete-route [domain name] --hostname [hostname]
Delete a service instance
You must unbind a service instance from any apps it is bound to before you can delete that service instance. Note:
- you do not need to delete an app’s service instances before you can delete that app
- a service instance can be bound to more than one app
Run
cf services
to see all service instances in your targeted space. You will see the output as per this example:name service plan bound apps last operation mystuff postgres small my-app create succeeded mydb mysql large not-my-app create succeeded
Run the following to unbind a service instance:
cf unbind-service APPLICATION SERVICE_NAME
where APPLICATION is the name of a deployed instance of your app (exactly as specified in your manifest or push command) and SERVICE_NAME is a unique descriptive name for this service instance, for example:
cf unbind-service my-app mystuff
Run
cf delete-service SERVICE_NAME
to delete that service instance.
Deploy a Docker image (experimental)
This section explains how to deploy an app from a Docker image. The role of the Docker image is to serve as a packaging format and the requirements for the app and its runtime environment are the same as for apps deployed using buildpacks. Configuration via manifest.yml also stays the same, albeit you should not specify buildpack. If you do, it will be ignored, which can create some confusion to anyone reading the manifest. Our platform currently supports deploying from the following:
- Docker Hub
- Docker Trusted Registry [external page] servers
- Docker registries that require authentication
Pushing local Docker images isn’t supported.
To deploy an app using a Docker image stored in Docker Hub via CF cli:
cf push myapp --docker-image dockerhuborg/app_image:tag
To deploy an app using a Docker image stored in Docker Trusted Registry (DTR) via CF cli:
cf push myapp --docker-image MY-PRIVATE-REGISTRY.DOMAIN:5000/image/name:tag
To deploy an app using a Docker image stored in a registry that requires authentication, follow the Cloud Foundry Docker image documentation instructions [external link].
You might notice that the staging process is simplified when deploying from a Docker image - this is because there is no need to build the app from the pushed code using a buildpack. Also, the buildpack for apps deployed from a Docker image will be reported as unknown
in the app information (cf app <myapp>
).
There are a few more specifics about Docker image support in Cloud Foundry:
- Local storage in each container instance is ephemeral. Every container launch will start with unmodified image.
- Traffic will be routed to the lowest exposed port (by
EXPOSE
command in Dockerfile). The PORT environment variable will be also set to this number. - Buildpack based apps use bash to execute the app start command (
bash -c <command>
), but Docker image based apps use sh (sh -c <command>
) - as bash presence cannot be assumed in your Docker image. - Privileged container mode is not supported. Features depending on this will not work.
- Only registries that use Docker Registry API V2 are supported.
Your responsibilities change if you use a Docker image instead of a buildpack. Refer to the responsibility model guidance for further information.
Docker Registry Availability Requirements
Deploying, scaling, restarting or restaging an app using a Docker image are all dependent on the Docker registry being available, because these actions require pulling the image from the registry.
Note that Cloud Foundry can restart your application due to circumstances outside of your direct control, such as platform scaling or deployments, or failure of the underlying hardware platform.
If Cloud Foundry attempts to pull the image from the registry when the registry is not available, your application instance will fail to start, and you will receive a Failed to create container
message. Once the Docker registry is available again, you will be able to re-deploy, restart or restage your app as required.
Experimental feature
Please note that this is currently only an experimental feature, meaning you can potentially encounter some unexpected behaviour or glitches. It is also possible that we might turn the feature off in the future. It should not be used in live services at this stage.
Lastly, our support for this functionality has lower priority than usual requests, so it is possible that responses to your queries regarding this will take a bit longer. However we are turning on this feature in order get feedback from service teams, so please contact support with any comments or to talk about use in production systems.
Applying security updates
When your app is built with a standard buildpack, you are responsible only for the code of your app. The platform provides both the buildpacks and also a safe and secure root filesystem (cflinuxfs2
). Buildpack based apps never have root access in their container, which adds another layer of security. We do periodically apply security and functionality updates to the buildpacks, container root FS and the platform itself.
When your app is deployed from Docker image, responsibility for the root filesystem and for the complete build of your app shifts to you. You need to ensure proper measures are applied to make your app and root image safe and with the latest security updates. We recommend you use one of the major and well supported linux distributions as your base container. This way you will be able to build an image with latest security patches easily.
Production checklist
Before deploying an app for production use, check the following:
- If your app uses a backing service, make sure that you have selected the high-availability plan for the service instance.
- You have a domain name for your service.
- You are running more than one instance of the app to ensure availability. Use
cf scale APPNAME -i INSTANCES
or amend the manifest file to add more running instances; see Scaling for more information. - You are prepared to use a blue-green deployment process [external link] for when the app needs to be updated or restarted (this avoids problems due to a known issue with the PaaS that can generate transient 404 errors).
- You have configured a health check [external link] by setting
health-check-type
tohttp
and settinghealth-check-http-endpoint
to an appropriate endpoint for your app.