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 app manifests for more information on the options available when you deploy an app.
Refer to the documentation on deploying an app to production 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
By default, all apps you deploy on Cloud Foundry are publicly accessible to everyone through the internet.
If you need to restrict access to a public app, for example to implement basic authentication, you should refer to the documentation on route services.
If you do not want your apps to be publicly accessible at all, you must deploy your apps on the apps.internal
domain. A common use case for this is that you have multiple micro-services that make up an overall app, and those micro-services must only be accessible by other micro-services in the app.
Private apps can communicate over any TCP-based protocol. If you wish to use TLS, you are responsible for the keys, certificates, protocol versions, and ciphers involved.
The following 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
Specify a private route in the private app’s manifest
Cloud Foundry uses routes 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
Refer to the Cloud Foundry documentation on routes for more information.
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.
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 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 PRIVATE_APPNAME --protocol tcp --port 8080
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.
Learn about How GOV.UK PaaS meets the NCSC Cloud Security Principles.
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.
Deploy an app to production
To deploy an app to a production environment, your department, agency or team must have a paid account with the GOV.UK PaaS.
Before you deploy an app to a production environment, you must set up a domain.
If you are a central government service using the GOV.UK domain, you must get a domain from GOV.UK for your service and set the DNS records required by your cdn-route service.
If you are using your own content distribution network (CDN), you must set up a domain by configuring your CDN.
You must also:
- build your app in line with the 12-factor app principles
- use a separate staging environment to test your app (refer to the case studies on managing orgs, users and spaces for more information)
- configure an
http
health check to allow Cloud Foundry to detect and attempt to replace unhealthy app instances
When you deploy an app to a production environment, you should:
- use zero downtime, rolling deploys
- run more than one instance of your app to make sure your app is always available
- select a high-availability plan for your app’s backing service if your app uses a backing service
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 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 documentation on knowing your responsibilities 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.
---
...
buildpacks:
- 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 is not 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 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 documentation on environment variables for more information.
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. Refer to the Cloud Foundry guide to deploying Ruby on Rails apps for more information.
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 does not 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 buildpacks: - 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 refer to the documentation on deploying an app to production.
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 buildpacks: - 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 refer to the documentation on deploying an app to production.
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 on specifying a Ruby version for more information.
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 documentation on configuring a production server for more information.
Troubleshooting asset precompilation
By default, the Rails buildpack performs asset precompilation during the staging phase. This is fine for most Rails apps, but it will not 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. Refer to the Cloud Foundry documentation on asset precompilation for more information.
Deploy a Node.js app
This section covers how to deploy a basic Node.js application to GOV.UK PaaS. Refer to the Cloud Foundry tips for Node.js applications for more information.
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 buildpacks: - 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
.
Refer to the Cloud Foundry tips for Node.js applications 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 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, 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:
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 on specifying a Node.js version for more information.
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.
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.
For more information, refer to the Cloud Foundry documentation on specifying a Python version.
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 does not already have one by runningpip freeze > requirements.txt
in the root of the local folder.Add the following lines to the
requirements.txt
file:whitenoise==5.2.0 # manages static assets waitress==2.0.0 # a pure python WSGI server that is a replacement for gunicorn
Tell Django to use
whitenoise
to serve static files. Insettings.py
within the project folder, add this line toMIDDLEWARE
, immediately aftermiddleware.security.SecurityMiddleware
:'whitenoise.middleware.WhiteNoiseMiddleware',
To serve the files so that they can be compressed and cached, add the following line to
settings.py
:STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
See the
whitenoise
documentation for details.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 buildpacks: - 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.
Deploying a JAR file
If your java application can be packaged as a self-executable JAR file then you can deploy it 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 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, refer to the Tomcat Container documentation.
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 or Clojure) with little or zero additional configuration. For more information, refer to the following examples of deploying applications using other frameworks and JVM-based languages:
- Embedded web server
- Grails
- Groovy
- Java Main
- Play Framework
- Servlet
- Spring Boot CLI
- Cloud Foundry Java Buildpack documentation
- Cloud Foundry tips for java developers for more information.
Deploy a .NET Core app
This section covers how to deploy a .NET Core application to GOV.UK PaaS using the dotnet-core buildpack.
Deploying an ASP.NET Core Web App
This example will walk through creating a simple “Hello World” web application using the dotnet
command line interface.
The instructions assume you have already carried out the setup process explained in the Get started section.
Install the dotnet core command line interface (CLI) tools
See Microsoft’s documentation for instructions on how to do this.
Create a new ASP.NET Core Web App using the dotnet CLI
dotnet new webapp --name your-app-name
Change directory into your new application’s directory
cd your-app-name
Create a manifest to describe how your application should be deployed
--- applications: - name: your-app-name buildpacks: - dotnet_core_buildpack memory: 256M
Pick a version of the .NET framework to target which is supported by the current buildpack
- Run
cf buildpacks
and look at the filename fordotnet_core_buildpack
to work out the version (for example, if the filename wasdotnet-core-buildpack-cflinuxfs3-v2.3.2.zip
the version of the buildpack would bev2.3.2
). - Visit the buildpack’s releases page, for example https://github.com/cloudfoundry/dotnet-core-buildpack/releases/tag/v2.3.2
- Check the versions of
dotnet-sdk
supported by the buildpack - you should usually use the latest supported version, for example 3.0.100 - Edit your
.csproj
file and change the contents of the<TargetFramework>
element to the target framework corresponding to the supported framework version (for example, usenetcoreapp3.0
for a 3.0.x version ofdotnet-sdk
). See Microsoft’s documentation on supported target framework versions. Create a
buildpack.yml
file to specify which version of the framework the buildpack should use:--- dotnet-core: sdk: 3.x
- Run
Push your application to GOV.UK PaaS
cf push
You have now deployed your .NET core application. Your application should now be accessible over HTTPS from the URL provided in the output.
Stopping and starting apps
Run the following in the command line to temporarily stop your app and free up memory from your quota:
cf stop APP_NAME
Users visiting your app’s URL will get the error:
404 Not Found: Requested route ('APP_NAME.APP_DOMAIN') does not exist.
Databases and other provisioned services will still be running, and GOV.UK PaaS will charge you for any paid plans or services.
Run the following to restart a stopped app:
cf start APP_NAME
Deleting apps
You should run cf target
to check which org and space you are in before you delete an app.
Run the following to delete an app:
cf delete APPNAME
Deleting app routes
Run the following to delete an app and that app’s routes at the same time, as long as those routes are not also mappped to other apps:
cf delete -r APPNAME
You can delete an app’s routes separately.
Run
cf routes
to get a list of all active routes in the current space. This command will also list information about the routes, including hostname and app domain.Run the following to delete the app’s routes:
cf delete-route DOMAIN_NAME --hostname HOSTNAME
Deleting 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. Example output: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 APP_NAME SERVICE_NAME
where:
- `APP_NAME` is the name of a deployed instance of your app exactly as specified in your manifest or push command
- `SERVICE_NAME` is a unique descriptive name for this service instance
- Run
cf delete-service SERVICE_NAME
to delete that service instance.
Deploy a Docker image
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 using 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 is not supported.
To deploy an app using a Docker image stored in Docker Hub using 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) using 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.
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.
- Images are cached based on tag. Using a tag like
latest
when doing quick iterations can result in errors. To prevent this, tags should be unique. For example, the time the image was created, or a git commit hash.
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.
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 (cflinuxfs3
). 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.