Platform.sh User Documentation

DDEV

Try for 30 days
Flexible, version-controlled infrastructure provisioning and development-to-production workflows
Activate your trial

DDEV is an open-source tool for local development environments. It allows you to use Docker in your workflows while maintaining a GitOps workflow. You get fully containerized environments to run everything locally without having to install tools (including the Platform.sh CLI, PHP, and Composer) on your machine.

Before you begin Anchor to this heading

You need:

  • A local copy of the repository for a Django project running on Platform.sh.

    To get one, run platform get PROJECT_ID .

    Alternatively, you can clone an integrated source repository and set the remote branch. To do so, run platform project:set-remote PROJECT_ID .

  • The Platform.sh CLI

  • DDEV installed on your computer.

    Make sure your computer meets the system requirements for DDEV.

    For the integration to run smoothly, you also need the following tools:

    • jq
    • base64
    • perl

    If you don’t have these already installed, use your normal package manager.

    To install DDEV, follow the DDEV documentation for your operating system.

    This installs the self-contained ddev command-line interface (CLI). For more information on ddev, run ddev help.

Assumptions Anchor to this heading

This example makes some assumptions, which you may need to adjust for your own circumstances.

It’s assumed you want to run a built-in lightweight development server with manage.py runserver. To match a production web server (such as Gunicorn or Daphne), modify those commands accordingly.

It’s generally assumed that Platform.sh is the primary remote for the project. If you use a source integration, the steps are identical in most cases. When they differ, the alternative is noted.

Set up DDEV Anchor to this heading

  1. Create a new environment off of production.

    platform branch new-feature main

    If you’re using a source integration, open a merge/pull request.

  2. Add DDEV configuration to the project.

    ddev config --auto
  3. Add a Python alias package to the configuration.

    ddev config --webimage-extra-packages python-is-python3
  4. Add an API token.

    To connect DDEV with your Platform.sh account, use a Platform.sh API token.

    First create an API token in the Console.

    Then add the token to your DDEV configuration. You can do so globally (easiest for most people):

    ddev config global --web-environment-add=PLATFORMSH
    _CLI_TOKEN=API_TOKEN

    You can also add the token only to the project:

    ddev config --web-environment-add=PLATFORMSH
    _CLI_TOKEN=API_TOKEN
  5. Connect DDEV to your project and the new-feature environment.

    The best way to connect your local DDEV to your Platform.sh project is through the Platform.sh DDEV add-on. To add it, run the following command:

    ddev get ddev/ddev-platformsh

    Answer the interactive prompts with your project ID and the name of the environment to pull data from.

    With the add-on, you can now run ddev platform <command> from your computer without needing to install the Platform.sh CLI.

  6. Update the DDEV PHP version.

    Python support in DDEV and the Platform.sh integration is in active development. At this time, the only officially supported runtime is PHP. With a few changes, the generated configuration can be modified to run local Django environments.

    A .ddev directory has been created in the repository containing DDEV configuration.

    In the .ddev/config.platformsh.yaml file, update the php_version attribute to a supported version, like 8.2.

    .ddev/config.platformsh.yaml
    # Leaving the generated line as is results in an error.
    # php_version: python:3.10
    php_version: 8.2
  7. Update the DDEV post-start hooks.

    The generated configuration contains a hooks.post-start attribute that contains Django’s hooks.build and hooks.deploy. Add another item to the end of that array with the start command defined in .platform.app.yaml:

    .ddev/docker-compose.django.yaml
    hooks:
        post-start:
            ...
            # Platform.sh start command
            - exec: python manage.py runserver 0.0.0.0:8000
    .ddev/docker-compose.django.yaml
    hooks:
        post-start:
            ...
            # Platform.sh start command
            - exec: pipenv run python manage.py runserver 0.0.0.0:8000
    .ddev/docker-compose.django.yaml
    hooks:
        post-start:
            ...
            # Platform.sh start command
            - exec: poetry run python manage.py runserver 0.0.0.0:8000
  8. Create a custom Docker Compose file to define the port exposed for the container you’re building, web:

    .ddev/docker-compose.django.yaml
    version: "3.6"
    services:
        web:
            expose:
                - 8000
            environment:
                - HTTP_EXPOSE=80:8000
                - HTTPS_EXPOSE=443:8000
            healthcheck:
                test: "true"
  9. Create a custom Dockerfile to install Python into the container.

    .ddev/web-build/Dockerfile.python
    RUN apt-get install -y python3.10 python3-pip
  10. Update your allowed hosts to include the expected DDEV domain suffix:

    APP_NAME/settings.py
    ALLOWED_HOSTS = [
        'localhost',
        '127.0.0.1',
        '.platformsh.site',
        '.ddev.site'
    ]
  11. Update your database configuration to include environment variables provided by DDEV:

    APP_NAME/settings.py
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql',
            'NAME': os.environ.get('POSTGRES_NAME'),
            'USER': os.environ.get('POSTGRES_USER'),
            'PASSWORD': os.environ.get('POSTGRES_PASSWORD'),
            'HOST': 'db',
            'PORT': 5432,
        }
    }

    This example assumes you have a PostgreSQL database with db as the relationship name. If you have a different setup, adjust the values accordingly.

  12. Start DDEV.

    Build and start up Django for the first time.

    ddev start

    If you have another process running, you may get an error such as the following:

    Failed to start django: Unable to listen on required ports, port 80 is already in use

    If you do, either cancel the running process on port 80 or do both of the following:

    • Edit router_http_port in .ddev/config.yaml to another port such as 8080.
    • Edit the services.web.environment variable HTTP_EXPOSE in ddev/docker-compose.django.yaml to HTTP_EXPOSE=8080:8000.
  13. Pull data from the environment.

    Exit the currently running process (CTRL+C) and then run the following command to retrieve data from the current Platform.sh environment:

    ddev pull platform
  14. Restart DDEV

    ddev restart

    You now have a local development environment that’s in sync with the new-feature environment on Platform.sh.

  15. When you finish your work, shut down DDEV.

    ddev stop

Next steps Anchor to this heading

You can now use your local environment to develop changes for review on Platform.sh environments. The following examples show how you can take advantage of that.

Onboard collaborators Anchor to this heading

It’s essential for every developer on your team to have a local development environment to work on. Place the local configuration into a script to ensure everyone has this. You can merge this change into production.

  1. Create a new environment called local-config.

  2. To set up a local environment for a new Platform.sh environment, create an executable script.

    touch init-local.sh && chmod +x init-local.sh
  3. Fill it with the following example, depending on your package manager:

    init-local.sh
    #!/usr/bin/env bash
    
    PROJECT=$1
    ENVIRONMENT=$2
    PARENT=$3
    
    # Create the new environment
    platform branch $ENVIRONMENT $PARENT
    
    # Configure DDEV
    ddev config --auto
    ddev config --web-environment-add PLATFORM_PROJECT=$PROJECT
    ddev config --web-environment-add PLATFORM_ENVIRONMENT=$ENVIRONMENT
    ddev config --webimage-extra-packages python-is-python3
    
    ddev get drud/ddev-platformsh
    
    # Update .ddev/config.platformsh.yaml
    #   1. hooks.post-start
    printf "  # Platform.sh start command\n  - exec: |\n      python manage.py runserver 0.0.0.0:8000" >> .ddev/config.platformsh.yaml
    #   2. php_version
    grep -v "php_version" .ddev/config.platformsh.yaml > tmpfile && mv tmpfile .ddev/config.platformsh.yaml
    printf "\nphp_version: 8.0" >> .ddev/config.platformsh.yaml
    
    # Create a docker-compose.django.yaml
    printf "
    version: \"3.6\"
    services:
        web:
            expose:
                - 8000
            environment:
                - HTTP_EXPOSE=80:8000
                - HTTPS_EXPOSE=443:8000
            healthcheck:
                test: \"true\"
    " > .ddev/docker-compose.django.yaml
    
    # Create Dockerfile.python
    printf "
    RUN apt-get install -y python3.10 python3-pip
    " > .ddev/web-build/Dockerfile.python
    
    ddev start
    ddev pull platform -y
    ddev restart
    init-local.sh
    #!/usr/bin/env bash
    
    PROJECT=$1
    ENVIRONMENT=$2
    PARENT=$3
    
    # Create the new environment
    platform branch $ENVIRONMENT $PARENT
    
    # Configure DDEV
    ddev config --auto
    ddev config --web-environment-add PLATFORM_PROJECT=$PROJECT
    ddev config --web-environment-add PLATFORM_ENVIRONMENT=$ENVIRONMENT
    ddev config --webimage-extra-packages python-is-python3
    
    ddev get drud/ddev-platformsh
    
    # Update .ddev/config.platformsh.yaml
    #   1. hooks.post-start
    printf "  # Platform.sh start command\n  - exec: |\n      pipenv run python manage.py runserver 0.0.0.0:8000" >> .ddev/config.platformsh.yaml
    #   2. php_version
    grep -v "php_version" .ddev/config.platformsh.yaml > tmpfile && mv tmpfile .ddev/config.platformsh.yaml
    printf "\nphp_version: 8.0" >> .ddev/config.platformsh.yaml
    
    # Create a docker-compose.django.yaml
    printf "
    version: \"3.6\"
    services:
        web:
            expose:
                - 8000
            environment:
                - HTTP_EXPOSE=80:8000
                - HTTPS_EXPOSE=443:8000
            healthcheck:
                test: \"true\"
    " > .ddev/docker-compose.django.yaml
    
    # Create Dockerfile.python
    printf "
    RUN apt-get install -y python3.10 python3-pip
    " > .ddev/web-build/Dockerfile.python
    
    ddev start
    ddev pull platform -y
    ddev restart
    init-local.sh
    #!/usr/bin/env bash
    
    PROJECT=$1
    ENVIRONMENT=$2
    PARENT=$3
    
    # Create the new environment
    platform branch $ENVIRONMENT $PARENT
    
    # Configure DDEV
    ddev config --auto
    ddev config --web-environment-add PLATFORM_PROJECT=$PROJECT
    ddev config --web-environment-add PLATFORM_ENVIRONMENT=$ENVIRONMENT
    ddev config --webimage-extra-packages python-is-python3
    
    ddev get drud/ddev-platformsh
    
    # Update .ddev/config.platformsh.yaml
    #   1. hooks.post-start
    printf "  # Platform.sh start command\n  - exec: |\n      poetry run python manage.py runserver 0.0.0.0:8000" >> .ddev/config.platformsh.yaml
    #   2. php_version
    grep -v "php_version" .ddev/config.platformsh.yaml > tmpfile && mv tmpfile .ddev/config.platformsh.yaml
    printf "\nphp_version: 8.0" >> .ddev/config.platformsh.yaml
    
    # Create a docker-compose.django.yaml
    printf "
    version: \"3.6\"
    services:
        web:
            expose:
                - 8000
            environment:
                - HTTP_EXPOSE=80:8000
                - HTTPS_EXPOSE=443:8000
            healthcheck:
                test: \"true\"
    " > .ddev/docker-compose.django.yaml
    
    # Create Dockerfile.python
    printf "
    RUN apt-get install -y python3.10 python3-pip
    " > .ddev/web-build/Dockerfile.python
    
    ddev start
    ddev pull platform -y
    ddev restart
  4. To commit and push the revisions, run the following command:

    git add . && git commit -m "Add local configuration" && git push platform local-config
  5. Merge the change into production.

Once the script is merged into production, any user can set up their local environment by running the following commands:

platform PROJECT_ID
cd PROJECT_NAME
./init-local.sh PROJECT_ID another-new-feature PRODUCTION_ENVIRONMENT_NAME

Sanitize data Anchor to this heading

It’s often a compliance requirement to ensure that only a minimal subset of developers within an organization have access to production data during their work. By default, your production data is automatically cloned into every child environment.

You can customize your deployments to include a script that sanitizes the data within every preview environment.

  1. Create a new environment called sanitize-non-prod.

  2. Follow the example on how to sanitize PostgreSQL with Django. This adds a sanitization script to your deploy hook that runs on all preview environments.

  3. Commit and push the revisions by running the following command:

    git add . && git commit -m "Add data sanitization" && git push platform sanitize-non-prod
  4. Merge the change into production.

    Once the script is merged into production, every preview environment created on Platform.sh and all local environments contain sanitized data free of your users’ personally identifiable information (PII).

Is this page helpful?