Managing apps
Connecting with SSH
When you deploy an app to GOV.UK PaaS, that app runs in a container.
If you use a standard buildpack, you can connect directly to an app’s container using SSH.
Connecting using SSH gives you secure access to change an app’s container.
If you make changes to your app’s container during an SSH session, these changes are not permanent and are specific to that app instance. You must push a new version of your app to make any permanent changes to your app.
Before you connect to an app’s container using SSH, you must:
- install the Cloud Foundry Command Line Interface (CLI)
- set up the correct SSH permissions on the app and the space the app is in
Run the following to start an SSH session:
cf ssh APPNAME
where
APPNAME
is the name of the app.The Cloud Foundry CLI will generate SSH keys for you.
Warning If you are using Cloud Foundry CLI version 6, run `cf v3-ssh APPNAMETo match your SSH environment to your app’s environment, run the following from within your SSH session shell:
/tmp/lifecycle/shell
Run
exit
to end the SSH session.
For more information, refer to the Cloud Foundry documentation on SSH session environments.
Connecting to multiple instances
If you’re running multiple instances of an app, you can connect to a specific app instance using SSH.
Each instance of an app has an index number. Cloud Foundry assigns index numbers to app instances when you create those app instances.
Run
cf app APPNAME
to see the app index numbers in the output. For example:requested state: started instances: 3/3 usage: 64M x 3 instances urls: myapp.london.cloudapps.digital last uploaded: Wed Dec 21 13:56:24 UTC 2016 stack: cflinuxfs3 buildpack: staticfile_buildpack . state since cpu memory disk details 0 running 2016-12-21 02:27:11 PM 3.0% 7.1M of 64M 6.8M of 1G 1 running 2016-12-21 02:44:46 PM 1.0% 3.5M of 64M 6.8M of 1G 2 running 2016-12-21 02:44:46 PM 1.0% 3.5M of 64M 6.8M of 1G
Run
cf ssh -i APP_INSTANCE_NUMBER APPNAME
to connect to a specific app instance.For example,
cf ssh -i 2 myapp
connects to the last app instance in step 1 of the example.
Connecting to a non-publicly available backing service
The PostgreSQL, MySQL and Redis backing services are not publicly available to everyone on the internet. You can only connect to these backing services from inside Cloud Foundry.
You should use the Conduit plugin to connect to PostgreSQL, MySQL or Redis from your local machine.
If you do not want to use Conduit, you can manually create an SSH tunnel to connect to these backing services from your local machine.
The cf ssh
command supports local port forwarding, which allows you to create tunnels from your local system to the app instance container.
The following example shows how to connect to a PostgreSQL service bound to your app using an SSH tunnel.
Run
cf env APPNAME
to show all environment variables for your app. Example output:$ cf env myapp Getting env variables for app myapp in org myoth / space myorg as randomuser... OK System-Provided: { "VCAP_SERVICES": { "postgres": [ { "credentials": { "host": "rdsbroker-01-ff-d2.cwm.eu-west-1.rds.amazonaws.com", "jdbcUrl": "jdbc:postgresql://rdsbroker-01-ff-d2.cwm.eu-west-1.rds.amazonaws.com:5432/rdsbroker_9f0_97_aa4?user=rdsbroker_9f0_97_aa4_owner\u0026password=xnYXthsgUFwPUOO", "name": "rdsbroker_9f0_97_aa4", "password": "xnYXthsgUFwPUOO", "port": 5432, "uri": "postgres://rdsbroker_9f0_97_aa4_owner:xnYXthsgUFwPUOO@rdsbroker-01-ff-d2.cwm.eu-west-1.rds.amazonaws.com:5432/rdsbroker_9f0_97_aa4", "username": "rdsbroker_9f0_97_aa4_owner" }, ...
Make a note of the:
- remote
"host":
- remote
"port"
- PostgreSQL
"username":
- PostgreSQL
"password:
- database
"name":
- remote
Create an SSH tunnel between your local port 6666 and your backing service’s remote host and port:
cf ssh myapp -T -L 6666:HOST:PORT
where:
HOST
is the remote"host":
from the previous stepPORT
is the remote"port"
from the previous step
Refer to the Cloud Foundry documentation on configuring an SSH tunnel for more information.
Warning When you run this command, you’re in a shell in your remote app container. Once you exit the shell, the shell closes the tunnel to the remote host and port.Open a new local command line interface and connect to the local port in
localhost:6666
using a PostgreSQL client:psql postgres://USERNAME:PASSWORD@localhost:6666/DATABASE_NAME
where:
USERNAME
is the PostgreSQL"username":
from step 1PASSWORD
is the PostgreSQL"password":
from step 1DATABASE_NAME
is the database"name":
from step 1
You have manually created an SSH tunnel to connect to your backing services from your local machine.
For a PostgreSQL backing service, you can also back up the PostgreSQL database using pg_dump
:
pg_dump postgres://USERNAME:PASSWORD@localhost:6666/DATABASE_NAME > db.dump
Handshake failure error
If you get the following error, you must enable SSH for your app:
FAILED
Error opening SSH connection: ssh: handshake failed: ssh:
unable to authenticate, attempted methods [none password],
no supported methods remain
Managing SSH permissions
Before you can connect to an app’s container with SSH, you must enable SSH for both the app and the space the app is in.
All new apps and spaces have SSH enabled by default. You can enable and disable SSH independently for each space and app.
Enabling SSH for an app
Check if SSH is enabled for an app:
cf ssh-enabled APPNAME
where
APPNAME
is the name of the app.If you get a message stating that SSH support is disabled for the app, enable SSH by running:
cf enable-ssh APPNAME
The
enable-ssh
command affects all running instances of an app.
Enabling SSH for a space
You must be an org manager or a space manager to enable SSH for a space.
Target the correct space and check if SSH is enabled in that space:
cf space-ssh-allowed SPACENAME
where
SPACENAME
is the name of the space.If you get a message stating that SSH support is disabled for the space, enable SSH by running:
cf allow-space-ssh SPACENAME
Limiting SSH access
You should disable SSH where it’s not needed. For example, you can disable SSH in the production
space where you host your live apps, but leave SSH enabled in your development
and testing
spaces.
Run cf disable-ssh APPNAME
and restart your app to disable SSH for that app.
Run cf disallow-space-ssh SPACENAME
to disable SSH for that space.
Further information
Refer to the Cloud Foundry documentation on accessing apps with SSH.
Scaling
You can manually scale your app to meet increasing demand. You can do this by:
- changing the number of app instances running
- increasing memory and disk space allocated to your app
Your organisation quotas limit the resources you can use for each app.
Changing the number of app instances
You can change the number of instances of your app running at the same time. Running more than one app instance:
- allows your app to handle increased traffic and demand as incoming requests are automatically load-balanced across all instances
- helps maintain high availability and makes it less likely that the failure of a single component will take down your app
For example, run the following command to set the number of app instances to 5:
cf scale APPNAME -i 5
You can also use the manifest to set the number of instances that will start when you push the app:
---
applications:
- name: APP_NAME
instances: 2
You should always run more than one instance when deploying an app to production.
Increasing memory or disk space
You can scale an app vertically by increasing the memory or disk space available to each instance of the app.
For example, this command increases the available memory for an app to 1 gigabyte:
cf scale APPNAME -m 1G
This command increases the disk space limit for an app to 512 megabytes:
cf scale APPNAME -k 512M
Further information
For more information, refer to the Cloud Foundry documentation on using cf scale
to scale an app in the Cloud Foundry docs.
Autoscaling
Apps can be configured to dynamically increase or decrease the number of running instances using autoscaling.
Scaling your app to fewer instances can reduce the cost during periods of low usage, eg at night.
Scaling your app based on throughput or average latency can improve the user experience of your app during periods of high traffic, eg before a submission deadline.
Scaling methods
There are two ways of scaling:
schedules
- scale apps based on time of day and day of week or monthscaling_rules
- scale apps based on metrics, eg average latency
Schedules and scaling rules can be used at the same time, or on their own.
Limits
There are two limits which you can apply to an autoscaling policy:
instance_max_count
- maximum number of instances to runinstance_min_count
- minimum number of instances to run
The maximum value for instance_max_count
is determined by your quota.
The minimum value for instance_min_count
is 1.
Metrics
You can scale your app based on some provided metrics:
memoryused
- how many megabytes of memory an app instance is usingmemoryutil
- percentage of memory utilization where50
is 50%cpu
- percentage of CPU utilization where100
is 100% of a single CPUresponsetime
- average time in milliseconds an app instance takes to respond to external HTTP requeststhroughput
- number of external HTTP requests processed per second
You can also scale your app based on custom metrics, please refer to the app-autoscaler user guide on GitHub.
Example
Ensure the autoscaling CLI plugin is installed:
cf install-plugin -r CF-Community app-autoscaler-plugin
Deploy your app, where
APPNAME
is the name of your application:cf push APPNAME
Create an autoscaler service to scale your app:
cf create-service autoscaler autoscaler-free-plan scale-APPNAME
Bind the autoscaler service to your app:
cf bind-service APPNAME scale-APPNAME
Create an autoscaling policy, the following policy will scale your app:
- adding one instance if CPU usage is greater than 50% for 120 seconds
- removing one instance if CPU usage is less than 50% for 120 seconds
It will ensure:
- there are never more than 5 instances of your app
- there are never fewer than 3 instances of your app
- scaling does not occur multiple times within a 60 second period
Create the following policy in a file called
policy.json
:{ "instance_min_count": 3, "instance_max_count": 5, "scaling_rules": [ { "metric_type": "cpu", "breach_duration_secs": 120, "threshold": 50, "operator": "<", "cool_down_secs": 60, "adjustment": "-1" }, { "metric_type": "cpu", "breach_duration_secs": 120, "threshold": 50, "operator": ">=", "cool_down_secs": 60, "adjustment": "+1" } ] }
Attach the autoscaling policy to your app:
cf attach-autoscaling-policy APPNAME policy.json
Observe the app scaling automatically:
cf autoscaling-history APPNAME
Example policies
Scale when throughput increases or decreases
Imagine you have an app which can handle approximately 100 requests per second per instance before the user experience becomes slow, and the app unreliable.
{
"instance_min_count": 3,
"instance_max_count": 9,
"scaling_rules": [
{
"metric_type": "throughput",
"breach_duration_secs": 60,
"threshold": 90,
"operator": "<",
"cool_down_secs": 60,
"adjustment": "-1"
},
{
"metric_type": "throughput",
"breach_duration_secs": 60,
"threshold": 90,
"operator": ">=",
"cool_down_secs": 60,
"adjustment": "+1"
}
]
}
This policy will scale your app:
- adding one instance if the average number of external HTTP requests per second per instance is greater than 90 for 60 seconds
- removing one instance if the average number of external HTTP requests per second per instance is less than 90 for 60 seconds
This policy will ensure:
- there are never more than 6 instances of your app
- there are never fewer than 3 instances of your app
This policy will avoid scaling multiple times within a 60 second period.
Scale during the day
Imagine you have an app which is used frequently during daytime working hours, but does not receive much traffic otherwise.
{
"instance_min_count": 2,
"instance_max_count": 4,
"scaling_rules": [
{
"metric_type": "throughput",
"breach_duration_secs": 60,
"threshold": 90,
"operator": "<",
"cool_down_secs": 60,
"adjustment": "-1"
},
{
"metric_type": "throughput",
"breach_duration_secs": 60,
"threshold": 90,
"operator": ">=",
"cool_down_secs": 60,
"adjustment": "+1"
}
],
"schedules": {
"timezone": "Europe/London",
"recurring_schedule": [
{
"start_time": "08:00",
"end_time": "18:00",
"days_of_week": [1, 2, 4, 5],
"instance_min_count": 4,
"instance_max_count": 8,
"initial_min_instance_count": 4
},
{
"start_time": "08:00",
"end_time": "18:00",
"days_of_week": [3],
"instance_min_count": 6,
"instance_max_count": 10,
"initial_min_instance_count": 6
}
]
}
}
This policy uses the same scaling rules as the previous example:
- adding one instance if the average number of external HTTP requests per second per instance is greater than 90 for 60 seconds
- removing one instance if the average number of external HTTP requests per second per instance is less than 90 for 60 seconds
This policy will ensure:
- there are between 6 and 10 instances during Wednesday working hours
- there are between 4 and 8 instances during working hours on other weekdays
- there are between 2 and 4 instances otherwise
Scale during the month
Imagine you have an app which is used frequently during the first week of the month, but does not receive much traffic otherwise.
{
"instance_min_count": 2,
"instance_max_count": 4,
"scaling_rules": [
{
"metric_type": "throughput",
"breach_duration_secs": 60,
"threshold": 90,
"operator": "<",
"cool_down_secs": 60,
"adjustment": "-1"
},
{
"metric_type": "throughput",
"breach_duration_secs": 60,
"threshold": 90,
"operator": ">=",
"cool_down_secs": 60,
"adjustment": "+1"
}
],
"schedules": {
"timezone": "Europe/London",
"recurring_schedule": [
{
"start_time": "06:00",
"end_time": "22:00",
"days_of_month": [1, 2, 3, 4, 5, 6, 7],
"instance_min_count": 6,
"instance_max_count": 10,
"initial_min_instance_count": 6
}
]
}
}
This policy uses the same scaling rules as the previous example:
- adding one instance if the average number of external HTTP requests per second per instance is greater than 90 for 60 seconds
- removing one instance if the average number of external HTTP requests per second per instance is less than 90 for 60 seconds
This policy will ensure:
- there are between 6 and 10 instances during daylight hours of the first week of the month
- there are between 2 and 4 instances otherwise
Tips for autoscaling policies
- Ensure that schedules do not overlap
- Small changes in scale which occur more often are better than large, infrequent changes
- Keep your autoscaling policies simple
- If your app should be highly available, ensure
instance_min_count
is at least 3
Further information
Refer to the app-autoscaler user guide on GitHub.
Quotas
Cloud Foundry capacity is managed by quotas. Quotas provide a reservation of application routes, memory, compute power, and service instances which your organisation cannot exceed. You can set individual application quotas to control how much of your quota each of your applications can use.
Quota allocations
Your organisation will be assigned a quota based on your stated needs. This will cover the app instances you run.
Your quota sets the following:
RAM: The amount of RAM available to your applications. The application also has a compute share derived from its memory limit.
Services: The number of service instances available to your organisation.
Paid services: Whether or not paid services are available.
postgres
is a paid service.Routes: The number of routes available to your applications (hostname and domain pairs where an application that exposes a listening port can be reached).
Our quotas are:
Name | RAM | Routes | Services |
---|---|---|---|
default (trial) | 5.12GB | 1000 | 10 |
small | 10.24GB | 1000 | 10 |
medium | 61.44GB | 1000 | 20 |
large | 102.40GB | 1000 | 40 |
xlarge | 204.80GB | 1000 | 80 |
2xlarge | 409.60GB | 1000 | 160 |
4xlarge | 819.20GB | 2000 | 320 |
8xlarge | 1638.40GB | 4000 | 720 |
To see your organisation quota, run the command:
cf org YOURORG
where YOURORG is your organisations’s name. (If you do not know the name, you can use cf orgs
to find out). This will produce an output which includes the name of the org’s current quota:
name: YOURORG
domains: my.domain,
quota: medium
spaces: space1, space2
isolation segments:
To see the details of that quota, run:
cf org-quota QUOTA
where QUOTA is the name of the quota that GOV.UK PaaS has assigned to your org.
Total Memory 60G
Instance Memory unlimited
Routes 1000
Services 20
Paid service plans allowed
App instance limit unlimited
Reserved Route Ports 0
To see all quotas available on the GOV.UK PaaS, run the command:
cf org-quotas
Quota limits
If a new application push
would exceed your organisation’s quota, the request will fail with status code 400
and a message describing the limit that would be exceeded.
Example:
Creating app APPLICATION in org ORG / space SPACE as USER...
FAILED
Server error, status code: 400, error code: 100007, message:
You have exceeded the memory limit for your organization's quota.
In this situation you have three options:
- Delete existing resources with
cf delete
,cf delete-service
,cf delete-route
or similar commands. - Reconfigure existing application quotas and redeploy.
- Request a quota change: contact us at gov-uk-paas-support@digital.cabinet-office.gov.uk.
Application quotas
As a PaaS tenant, you can divide your organisation’s quota capacity amongst your applications as you see fit, by way of application quotas. Application limits are specified in your application manifest or as cf push
command line options.
Use the following commands to set application quota options (in each pair below, the first is the version to use in the manifest, and the second is the command line version.)
memory:
/-m
Your application’s memory limit. An application’s compute limit is derived from its memory limit (see below).
disk_quota:
/-k
The maximum amount of disk space available to your app.
instances:
/-i
Sets the number of application instances to launch. Each additional instance receives the same memory and disk reservation. An application with a manifest specifying
memory: 256M
andinstances: 4
would reserve 1GB (256M x 4) total.For a production application, you should always launch more than one instance. See Scaling for more information.
Memory share and compute share
Your application’s compute limit is derived from its memory limit. Each application receives a guaranteed compute share equal to its relative share of memory.
Your application will be guaranteed to receive a portion of the vCPU compute power equal to its portion of memory allocation. In other words, it will receive at least this much vCPU time even if there are other applications competing for time.
Your application will be offered 100% of the vCPU compute power. If no other applications are running, the app can use all the computer power available. If there are other applications competing for time, each application’s guaranteed share determines how much time it will receive.
The application cannot access more than the specified amount of memory.
Application quota sizing
The environment default of 512MB
memory
is sufficient for most applications. Static sites and utility applications such as schedulers or loaders may require less. Usecf app APPNAME
to check your application’s current memory and compute utilisation.requested state: started instances: 1/1 usage: 128M x 1 instances urls: last uploaded: Wed Jul 22 20:09:56 UTC 2015 state since cpu memory disk #0 running 2015-07-30 05:58:11 PM 0.0% 94.6M of 128M 80.4M of 128M
Any application which exceeds its memory quota will be automatically restarted. Use
cf events APPNAME
to look for ‘out of memory’ crashes.... description ... index: 0, reason: CRASHED, exit_description: out of memory, exit_status: 255
Redirecting all traffic
If a site moves to a different domain name, you can use a simple static site with a custom nginx.conf
file to redirect all traffic from the old domain to the new domain. Example nginx.conf
site for NEW_DOMAIN_NAME
:
worker_processes 1;
daemon off;
error_log <%= ENV["APP_ROOT"] %>/nginx/logs/error.log;
events { worker_connections 1024; }
http {
server {
listen <%= ENV["PORT"] %>;
server_name localhost;
return 301 $scheme://NEW_DOMAIN_NAME$request_uri;
}
}
Deploy your application to NEW_DOMAIN_NAME
and then cf push
a simple static site with that nginx.conf
configuration to the old domain name. You can see a full working example here.
You can read more about nginx customization.
App restarts
Your app can restart without you telling it to, due to:
- Cloud Foundry changes, such as platform upgrades or operating system patches
- an unexpected issue, such as your app instance running out of memory or disk space
Cloud Foundry changes
If your app processes take more than 10 seconds to finish, those processes will be affected by a Cloud Foundry-driven restart. Cloud Foundry will send a termination signal (SIGTERM
) to any apps it wants to restart. To shut down cleanly, apps must finish any requests within 10 seconds of receiving the termination signal.
If the app does not respond in time, Cloud Foundry will send a SIGKILL
signal to terminate the app. The app will not shut down cleanly and requests may fail.
If your app has more than one instance, the running instances will not restart at the same time. This makes sure that there are always available instances for your app.
For more information, refer to the Cloud Foundry documentation on how:
- to configure Cloud Foundry for high availability
- Cloud Foundry moves your app instances between servers using evacuations
- Cloud Foundry requests a shutdown of your app instance
404s after commands that restart your app
After you use a command that restarts application instances, such as cf push
or cf restart
, your app may temporarily return incorrect 404 errors instead of returning a 5XX error. Apart from the brief downtime, this may lead to problems if the 404 is cached, or visiting web crawling bots (as used by search engines) receive a 404.
Commands known to do this are:
cf push
cf restage
cf restart
cf scale
when changing disk or memory limits or forcing a restart
We are working on a fix to prevent this happening.
Until this fix is live, you should use a blue-green deployment process. This is where you have two versions of an app, one that is ‘live’ and one that is undergoing an update or restart. There are plugins for the Cloud Foundry command line client to help this process. We recommend the cf-blue-green-deploy plugin.