DDEV
Back to home
On this page
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
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 onddev
, runddev help
.
Assumptions
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
-
Create a new environment off of production.
platform branch new-feature main
If you’re using a source integration, open a merge/pull request.
-
Add DDEV configuration to the project.
ddev config --auto
-
Add a Python alias package to the configuration.
ddev config --webimage-extra-packages python-is-python3
-
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
-
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. -
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 thephp_version
attribute to a supported version, like8.2
..ddev/config.platformsh.yaml# Leaving the generated line as is results in an error. # php_version: python:3.10 php_version: 8.2
-
Update the DDEV
post-start
hooks.The generated configuration contains a
hooks.post-start
attribute that contains Django’shooks.build
andhooks.deploy
. Add another item to the end of that array with the start command defined in.platform.app.yaml
:.ddev/docker-compose.django.yamlhooks: post-start: ... # Platform.sh start command - exec: python manage.py runserver 0.0.0.0:8000
.ddev/docker-compose.django.yamlhooks: post-start: ... # Platform.sh start command - exec: pipenv run python manage.py runserver 0.0.0.0:8000
.ddev/docker-compose.django.yamlhooks: post-start: ... # Platform.sh start command - exec: poetry run python manage.py runserver 0.0.0.0:8000
-
Create a custom Docker Compose file to define the port exposed for the container you’re building,
web
:.ddev/docker-compose.django.yamlversion: "3.6" services: web: expose: - 8000 environment: - HTTP_EXPOSE=80:8000 - HTTPS_EXPOSE=443:8000 healthcheck: test: "true"
-
Create a custom
Dockerfile
to install Python into the container..ddev/web-build/Dockerfile.pythonRUN apt-get install -y python3.10 python3-pip
-
Update your allowed hosts to include the expected DDEV domain suffix:
APP_NAME/settings.pyALLOWED_HOSTS = [ 'localhost', '127.0.0.1', '.platformsh.site', '.ddev.site' ]
-
Update your database configuration to include environment variables provided by DDEV:
APP_NAME/settings.pyDATABASES = { '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. -
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 as8080
. - Edit the
services.web.environment
variableHTTP_EXPOSE
inddev/docker-compose.django.yaml
toHTTP_EXPOSE=8080:8000
.
- Edit
-
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
-
Restart DDEV
ddev restart
You now have a local development environment that’s in sync with the
new-feature
environment on Platform.sh. -
When you finish your work, shut down DDEV.
ddev stop
Next steps
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
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.
-
Create a new environment called
local-config
. -
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
-
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
-
To commit and push the revisions, run the following command:
git add . && git commit -m "Add local configuration" && git push platform local-config
-
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
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.
-
Create a new environment called
sanitize-non-prod
. -
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.
-
Commit and push the revisions by running the following command:
git add . && git commit -m "Add data sanitization" && git push platform sanitize-non-prod
-
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).