How to Manage Services in App Platform

App Platform is a Platform-as-a-Service (PaaS) offering that allows developers to publish code directly to DigitalOcean servers without worrying about the underlying infrastructure.


The usual app creation process will create a service by default; you only need to follow this process if you’re creating another resource for your app that needs an internet-accessible endpoint. If your resource only needs to be internally accessible, create a internal service instead. If you don’t need this resource to be internet-accessible, create a worker instead.

Add a Service to an App Using Automation

You can add a service to an app using the CLI’s app update command or the API’s app update endpoint. To add a service, update the app’s spec with the service’s specifications and submit the spec using the following command or endpoint.

How to Add a Service to an App Using the DigitalOcean CLI
  1. Install doctl, the DigitalOcean command-line tool.

  2. Create a personal access token and save it for use with doctl.

  3. Use the token to grant doctl access to your DigitalOcean account.

              doctl auth init
              
  4. Finally, run doctl apps update. Basic usage looks like this, but you can read the usage docs for more details:

                doctl apps update <app id> [flags]
              

    The following example updates an app with the ID f81d4fae-7dec-11d0-a765-00a0c91e6bf6 using an app spec located in a directory called /src/your-app.yaml. Additionally, the command returns the updated app’s ID, ingress information, and creation date:

                  doctl apps update f81d4fae-7dec-11d0-a765-00a0c91e6bf6 --spec src/your-app.yaml --format ID,DefaultIngress,Created
                
How to Add a Service to an App Using the DigitalOcean API
  1. Create a personal access token and save it for use with the API.

  2. Send a PUT request to https://api.digitalocean.com/v2/apps/{id}

    cURL

    Using cURL:

                    curl -X PUT \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $DIGITALOCEAN_TOKEN" \
    "https://api.digitalocean.com/v2/apps/{id}" \
    -d '{"alerts":[{"rule":"DEPLOYMENT_FAILED"},{"rule":"DOMAIN_FAILED"}],"domains":[{"domain":"example.com","type":"PRIMARY","zone":"example.com"}],"envs":[{"key":"API_KEY","scope":"RUN_AND_BUILD_TIME","type":"SECRET","value":"EV[1:zqiRIeaaYK/NqctZDYzy6t0pTrtRDez8:wqGpZRrsKN5nPhWQrS479cfBiXT0WQ==]"}],"features":["buildpack-stack=ubuntu-22"],"ingress":{},"name":"example-app","region":"nyc","services":[{"autoscaling":{"max_instance_count":4,"metrics":{"cpu":{"percent":70}},"min_instance_count":2},"git":{"branch":"main","repo_clone_url":"https://github.com/digitalocean/sample-nodejs.git"},"internal_ports":[8080],"log_destinations":[{"name":"your_log_consumer_name","open_search":{"endpoint":"logs.example.com:12345","basic_auth":{"user":"doadmin","password":"1234567890abcdef"},"index_name":"example-index","cluster_name":"example-cluster"}}],"name":"sample-nodejs","run_command":"yarn start","source_dir":"/"}]}'
                  

    Python

                    import os
    from pydo import Client
    
    client = Client(token=os.environ.get("DIGITALOCEAN_TOKEN"))
    req = {
    "spec": {
        "name": "web-app-01",
        "region": "nyc",
        "domains": [
            {
                "domain": "app.example.com",
                "type": "DEFAULT",
                "wildcard": True,
                "zone": "example.com",
                "minimum_tls_version": "1.3",
            }
        ],
        "services": [],
        "static_sites": [
            {
                "cors": {
                    "allow_origins": [
                        {"exact": "https://www.example.com"},
                        {"regex": "^.*example.com"},
                    ],
                    "allow_methods": [
                        "GET",
                        "OPTIONS",
                        "POST",
                        "PUT",
                        "PATCH",
                        "DELETE",
                    ],
                    "allow_headers": ["Content-Type", "X-Custom-Header"],
                    "expose_headers": ["Content-Encoding", "X-Custom-Header"],
                    "max_age": "5h30m",
                    "allow_credentials": False,
                },
                "routes": [{"path": "/api", "preserve_path_prefix": True}],
            }
        ],
        "jobs": [
            {
                "name": "api",
                "gitlab": {
                    "branch": "main",
                    "deploy_on_push": True,
                    "repo": "digitalocean/sample-golang",
                },
                "image": {
                    "registry": "registry.hub.docker.com",
                    "registry_type": "DOCR",
                    "repository": "origin/master",
                    "tag": "latest",
                },
                "dockerfile_path": "path/to/Dockerfile",
                "build_command": "npm run build",
                "run_command": "bin/api",
                "source_dir": "path/to/dir",
                "envs": [
                    {
                        "key": "BASE_URL",
                        "scope": "BUILD_TIME",
                        "type": "GENERAL",
                        "value": "http://example.com",
                    }
                ],
                "environment_slug": "node-js",
                "log_destinations": {
                    "name": "my_log_destination",
                    "papertrail": {
                        "endpoint": "https://mypapertrailendpoint.com"
                    },
                    "datadog": {
                        "endpoint": "https://mydatadogendpoint.com",
                        "api_key": "abcdefghijklmnopqrstuvwxyz0123456789",
                    },
                    "logtail": {
                        "token": "abcdefghijklmnopqrstuvwxyz0123456789"
                    },
                   "open_search": {
                        "endpoint": "https://myopensearchendpoint.com:9300"
                        "index_name": "logs"
                        "basic_auth": {
                            "user": "doadmin",
                            "password": "password"
                        }
                    },
                },
                "instance_count": 2,
                "instance_size_slug": "apps-s-1vcpu-0.5gb",
                "kind": "PRE_DEPLOY",
            }
        ],
        "workers": [
            {
                "name": "api",
                "gitlab": {
                    "branch": "main",
                    "deploy_on_push": True,
                    "repo": "digitalocean/sample-golang",
                },
                "image": {
                    "registry": "registry.hub.docker.com",
                    "registry_type": "DOCR",
                    "repository": "origin/master",
                    "tag": "latest",
                },
                "dockerfile_path": "path/to/Dockerfile",
                "build_command": "npm run build",
                "run_command": "bin/api",
                "source_dir": "path/to/dir",
                "envs": [
                    {
                        "key": "BASE_URL",
                        "scope": "BUILD_TIME",
                        "type": "GENERAL",
                        "value": "http://example.com",
                    }
                ],
                "environment_slug": "node-js",
                "log_destinations": {
                    "name": "my_log_destination",
                    "papertrail": {
                        "endpoint": "https://mypapertrailendpoint.com"
                    },
                    "datadog": {
                        "endpoint": "https://mydatadogendpoint.com",
                        "api_key": "abcdefghijklmnopqrstuvwxyz0123456789",
                    },
                    "logtail": {
                        "token": "abcdefghijklmnopqrstuvwxyz0123456789"
                    },
                   "open_search": {
                        "endpoint": "https://myopensearchendpoint.com:9300"
                        "index_name": "logs"
                        "basic_auth": {
                            "user": "doadmin",
                            "password": "password"
                        }
                    },
                },
                "instance_count": 2,
                "instance_size_slug": "apps-s-1vcpu-0.5gb",
            }
        ],
        "functions": [
            {
                "cors": {
                    "allow_origins": [
                        {"exact": "https://www.example.com"},
                        {"regex": "^.*example.com"},
                    ],
                    "allow_methods": [
                        "GET",
                        "OPTIONS",
                        "POST",
                        "PUT",
                        "PATCH",
                        "DELETE",
                    ],
                    "allow_headers": ["Content-Type", "X-Custom-Header"],
                    "expose_headers": ["Content-Encoding", "X-Custom-Header"],
                    "max_age": "5h30m",
                    "allow_credentials": False,
                },
                "routes": [{"path": "/api", "preserve_path_prefix": True}],
                "name": "api",
                "source_dir": "path/to/dir",
                "alerts": [
                    {
                        "rule": "CPU_UTILIZATION",
                        "disabled": False,
                        "operator": "GREATER_THAN",
                        "value": 2.32,
                        "window": "FIVE_MINUTES",
                    }
                ],
                "envs": [
                    {
                        "key": "BASE_URL",
                        "scope": "BUILD_TIME",
                        "type": "GENERAL",
                        "value": "http://example.com",
                    }
                ],
                "gitlab": {
                    "branch": "main",
                    "deploy_on_push": True,
                    "repo": "digitalocean/sample-golang",
                },
                "log_destinations": {
                    "name": "my_log_destination",
                    "papertrail": {
                        "endpoint": "https://mypapertrailendpoint.com"
                    },
                    "datadog": {
                        "endpoint": "https://mydatadogendpoint.com",
                        "api_key": "abcdefghijklmnopqrstuvwxyz0123456789",
                    },
                    "logtail": {
                        "token": "abcdefghijklmnopqrstuvwxyz0123456789"
                    },
                   "open_search": {
                        "endpoint": "https://myopensearchendpoint.com:9300"
                        "index_name": "logs"
                        "basic_auth": {
                            "user": "doadmin",
                            "password": "password"
                        }
                    },
                },
            }
        ],
        "databases": [
            {
                "cluster_name": "cluster_name",
                "db_name": "my_db",
                "db_user": "superuser",
                "engine": "PG",
                "name": "prod-db",
                "production": True,
                "version": "12",
            }
        ],
    }
    }
    update_resp = client.apps.update(id="bb245ba", body=req)
                  

Add a Service to an App Using the Control Panel

  1. In the Apps section of the DigitalOcean Control Panel, select your app, then click the Create dropdown and choose Create Resources From Source Code to add a Web Service.
Resources screen
  1. Select the repository service to retrieve your source code from, either: GitHub, GitLab, DigitalOcean Container Registry, Docker Hub, or a sample app. If you are connecting to your repository from DigitalOcean for the first time, you will need to click the Manage Access button to provide DigitalOcean access to the repositories or containers, then refresh this page.

  2. Select the repository from the Repository drop-down list. Next, select which branch of the source repo you’d like to use as the source. Optionally, for monorepos, specify the folder that contains the source in the Source Directory field. For containers, specify the image tag to use. Click Next.

    App Platform will inspect the code, select an appropriate resource type and also detect any appropriate build and run commands.

Create web service

To change to a different resource type, click the edit icon to open the Settings page of the resource. Click Edit next to Resource Type, choose another option from the Type drop-down list. Click Save to confirm your changes.

In the settings page, you can also change the resource’s name, view the resource’s buildpacks, edit its build and run commands, edit the HTTP port and the request route, and more. Click Save to confirm your changes.

Create web service settings
  1. Optionally, if you want to specify additional resources, click the Add Additional Resource From Source link, repeat the procedure and click Next.

  2. If you need to use environment variables, click Edit to the right of the resource name and supply them. Click the Encrypt checkbox to ensure a variable’s value is obscured in all build, deploy, and application logs.

    To specify an app-level environment variable, click Edit to the right of Global. Click Save and then click Next.

    See How to Use Environment Variables in App Platform for more details.

    Resources env variables
  3. Review the resources, environment variables and pricing, and click Create Resources.

Note
The service must bind to and expose the HTTP port on the network interface 0.0.0.0 , rather than on the localhost (localhost) or loopback interface (127.0.0.1).

Full HTTP request path preservation for services is not available in the control panel. Instead, set the preserve_path_prefix annotation in the App Spec to true.

Edit a Service

In the Apps section of the DigitalOcean Control Panel, select your app and click on the Settings tab. Click the Web Service you’d like to edit.

You can use the configuration settings you see here to change the Web Service’s scaling behavior, modify environment variables, edit commands, and more.

Destroy a Service

In the Apps section of the DigitalOcean Control Panel, select your app and click on the Settings tab. Click on the Web Service you’d like to destroy.

You can destroy the Web Service by clicking the Destroy Component button on the bottom of the page and entering its name to confirm your selection.

Create an Internal Service

Internal services are accessible to other components in the app’s private network. They do not have ports or endpoints exposed to the public internet.

You can create an internal service by closing the ports on an existing service or by updating an app’s spec with the internal_ports field.

Create an Internal Service Using the Control Panel

To create an internal service from the control panel, click your app and then click the Settings tab. From the Settings tab, select the service you want to make internal, scroll down to the Ports section, and then click Edit.

A screenshot of the Port section of an app. The internal port field is set to 81 and the Public HTTP Port is set to 8080.

In the Ports section, leave the Public HTTP Port field blank to close the public port. Then click the Add internal ports for private networking checkbox and add the internal port you want to open in the Internal Port field. You can add additional internal ports by clicking Add internal port and repeating this step.

Once you have specified the ports you want to add, click Save. This redeploys the app with the new internal ports.

Create an Internal Service Using the App Spec

To create an internal service using the app spec, remove any existing http_port fields from the target service object and then add the internal_ports field to the service:

    
        
            
services:
- environment_slug: go
  github:
    branch: master
    deploy_on_push: true
    repo: digitalocean/sample-golang
  instance_count: 1
  instance_size_slug: basic-xxs
  internal_ports:
  - 8080
  name: internal-service
  run_command: bin/sample-golang

        
    

The example service above is an internal service because it has no HTTP port or route, so it is inaccessible from the public internet, but exposes port 8080 internally, so workers and other services can reach it.

Add a Function

To add Functions, adjust your app spec like so:

name: go-random
region: nyc
functions:
- name: go-api
  github:
    repo: digitalocean/sample-functions-golang-random
    branch: master
    deploy_on_push: true

This process requires you to authorize to GitHub and specify the region you want to create the Function in. You can also delete the region field to automatically create the Function in the datacenter closest to you.