diff --git a/deployment/docker-compose.md b/deployment/docker-compose.md index b74a94aebca..c9e96ced7d9 100644 --- a/deployment/docker-compose.md +++ b/deployment/docker-compose.md @@ -1,84 +1,88 @@ # Deploying with Docker Compose -While [Docker Compose](https://docs.docker.com/compose/) is mainly known and used in a development environment, it [can -actually be used in production too](https://docs.docker.com/compose/production/). This is especially suitable for prototyping +While [Docker Compose](https://docs.docker.com/compose/) is mainly known and used in a development environment, it [can be used in production too](https://docs.docker.com/compose/production/). This is especially suitable for prototyping or small-scale deployments, where the robustness (and the associated complexity) of [Kubernetes](kubernetes.md) is not required. -It is recommended that you build the Docker images in a [CI (continuous integration)](https://en.wikipedia.org/wiki/Continuous_integration) -job, or failing which, on your development machine. The built images should then be pushed to a [container registry](https://docs.docker.com/registry/introduction/), -e.g. [Docker Hub](https://hub.docker.com/), [Google Container Registry](https://cloud.google.com/container-registry/), -[GitLab Container Registry](https://docs.gitlab.com/ee/user/packages/container_registry/). On the production server, you -would pull the pre-built images from the container registry. This maintains a separation of concerns between the build -environment and the production environment. +API Platform provides Docker images and a Docker Compose definition optimized for production usage. +In this tutorial, we will learn how to deploy our Symfony application on a single server using Docker Compose. -## Deploying for Production +Note: this tutorial has been adapted from [the Symfony Docker documentation](https://github.com/dunglas/symfony-docker/blob/main/docs/production.md). -To build images for production, you have to use the `docker-compose.prod.yml` file with Docker Compose. +## Preparing a Server -## Building and Pushing the Docker Images +To deploy your application in production, you need a server. +In this tutorial, we will use a virtual machine provided by DigitalOcean, but any Linux server can work. +If you already have a Linux server with Docker Compose installed, you can skip straight to [the next section](#configuring-a-domain-name). -These steps should be performed in a CI job (recommended) or on your development machine. +Otherwise, use [this affiliate link](https://m.do.co/c/5d8aabe3ab80) to get $100 of free credit, create an account, then click on "Create a Droplet". +Then, click on the "Marketplace" tab under the "Choose an image" section and search for the app named "Docker". +This will provision an Ubuntu server with the latest versions of Docker and Docker Compose already installed! -1. Make sure the environment variables required for the build are set. +For test purposes, the cheapest plan will be enough. For real production usage, you'll probably want to pick a plan in the "general purpose" section that will fit your needs. - If you are building the images in a CI job, these environment variables should be set as part of your CI job's environment. +![Deploying a Symfony app on DigitalOcean with Docker Compose](digitalocean-droplet.png) - If you are building on your development machine, you could set the environment variables in the `.env` file at the - top level of the distribution project (not to be confused with `api/.env` which is used by the Symfony application). - For example: +You can keep the defaults for other settings or tweak them according to your needs. +Don't forget to add your SSH key or to create a password, then press the "Finalize and create" button. - ```shell - ADMIN_IMAGE=registry.example.com/api-platform/admin - CLIENT_IMAGE=registry.example.com/api-platform/client - NGINX_IMAGE=registry.example.com/api-platform/nginx - PHP_IMAGE=registry.example.com/api-platform/php - REACT_APP_API_ENTRYPOINT=https://api.example.com - VARNISH_IMAGE=registry.example.com/api-platform/varnish - ``` +Then, wait a few seconds while your Droplet is provisioning. +When your Droplet is ready, use SSH to connect: - **Note**: `REACT_APP_API_ENTRYPOINT` must be an exact match of the target domain name where your API will be accessed - from, since its value is [embedded during build time](https://create-react-app.dev/docs/adding-custom-environment-variables). - See [this discussion for possible workarounds](https://github.com/facebook/create-react-app/issues/2353) if this limitation - is unacceptable for your project. +```console +ssh root@ +``` -2. Build the Docker images: +## Configuring a Domain Name - ```shell - docker-compose -f docker-compose.yml -f docker-compose.prod.yml build --pull - ``` +In most cases, you'll want to associate a domain name with your website. +If you don't own a domain name yet, you'll have to buy one through a registrar. +Use [this affiliate link](https://gandi.link/f/93650337) to redeem a 20% discount at Gandi.net. -3. Push the built images to the container registry: +Then create a DNS record of type `A` for your domain name pointing to the IP address of your server. - ```shell - docker-compose -f docker-compose.yml -f docker-compose.prod.yml push - ``` +Example: -## Pulling the Docker Images and Running the Services +```dns +your-domain-name.example.com. IN A 207.154.233.113 +```` -These steps should be performed on the production server. +Example in Gandi's UI: -1. Make sure the environment variables required are set. +![Creating a DNS record at Gandi.net](gandi-dns.png) - You could set the environment variables in the `.env` file at the top level of the distribution project (not to be - confused with `api/.env` which is used by the Symfony application). For example: +Note: Let's Encrypt, the service used by default by API Platform to automatically generate a TLS certificate, doesn't support using bare IP addresses. +Using a domain name is mandatory to use Let's Encrypt. - ```shell - SERVER_NAME=api.example.com - MERCURE_PUBLISHER_JWT_KEY=someKey - MERCURE_SUBSCRIBER_JWT_KEY=someKey - ``` +## Deploying - **Important**: Please make sure to change all the passwords, keys and secret values to your own. +Copy your project on the server using `git clone`, `scp` or any other tool that may fit your needs. +If you use GitHub, you may want to use [a deploy key](https://docs.github.com/en/developers/overview/managing-deploy-keys#deploy-keys). +Deploy keys are also [supported by GitLab](https://docs.gitlab.com/ee/user/project/deploy_keys/). -2. Pull the Docker images. +Example with Git: - ```console - docker-compose -f docker-compose.yml -f docker-compose.prod.yml pull - ``` +```console +git clone git@github.com:/.git +``` -3. Bring up the services. +Go into the directory containing your project (``), and start the app in production mode: - ```console - docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d - ``` +```console +SERVER_NAME=your-domain-name.example.com \ +APP_SECRET=ChangeMe \ +POSTGRES_PASSWORD=ChangeMe \ +CADDY_MERCURE_JWT_SECRET=ChangeMe \ +docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d +``` + +Be sure to replace `your-domain-name.example.com` with your actual domain name and to set the values of `APP_SECRET`, `CADDY_MERCURE_JWT_SECRET` to cryptographically secure random values. + +Your server is up and running, and a Let's Encrypt HTTPS certificate has been automatically generated for you. +Go to `https://your-domain-name.example.com` and enjoy! + +## Deploying on Multiple Nodes + +If you want to deploy your app on a cluster of machines, we recommend using [Kubernetes](kubernetes.md). +You can use [Docker Swarm](https://docs.docker.com/engine/swarm/stack-deploy/), +which is compatible with the provided Compose files. diff --git a/deployment/images/digitalocean-droplet.png b/deployment/images/digitalocean-droplet.png new file mode 100644 index 00000000000..65f19aa7994 Binary files /dev/null and b/deployment/images/digitalocean-droplet.png differ diff --git a/deployment/images/gandi-dns.png b/deployment/images/gandi-dns.png new file mode 100644 index 00000000000..b2a2377e00e Binary files /dev/null and b/deployment/images/gandi-dns.png differ diff --git a/deployment/index.md b/deployment/index.md index 50799680b15..2227b8e4714 100644 --- a/deployment/index.md +++ b/deployment/index.md @@ -1,20 +1,20 @@ # Deploying API Platform Applications -API Platform apps are super easy to deploy in production on most cloud providers thanks to the native integration with -[Kubernetes](kubernetes.md). +API Platform apps are super easy to deploy in production thanks to the [Docker Compose definetion](docker-compose.md) and to the [Kubernetes chart](kubernetes.md) we provide. -The server part of API Platform is basically a standard Symfony application, which you can also easily [deploy on your -own servers](http://symfony.com/doc/current/deployment.html). Documentation for deploying on various container [orchestration](https://en.wikipedia.org/wiki/Orchestration_(computing)) -tools and PaaS (Platform as a Service) are also available: +We strongly recommend using Kubernetes or Docker Compose to deploy your apps. -* [Deploying to a Kubernetes Cluster](kubernetes.md) -* [Deploying with Docker Compose](docker-compose.md) -* [Deploying on Heroku](heroku.md) -* [Deploying on Platform.sh](https://platform.sh/blog/deploy-api-platform-on-platformsh) +If you want to play with a local Kubernetes cluster, read [how to deploy an API Platform project on Minikube](minikube.md). -The clients are [Create React App](https://create-react-app.dev/) skeletons. You can deploy them in a wink -on any static website hosting service (including [Netlify](https://www.netlify.com/), [Firebase Hosting](https://firebase.google.com/docs/hosting/), -[GitHub Pages](https://pages.github.com/), or [Amazon S3](https://docs.aws.amazon.com/en_us/AmazonS3/latest/dev/WebsiteHosting.html) -by following [the relevant documentation](https://create-react-app.dev/docs/deployment/). +If you don't want to use Docker, keep in mind that the server application of API Platform is a standard Symfony project, +while the Progressive Web Application is a standard Next.js project:

JWT screencast
Watch the Animated Deployment with Ansistrano screencast

+ +* [Deploying the Symfony application](https://symfony.com/doc/current/deployment.html) +* [Deployin the Next.js application](https://nextjs.org/docs/deployment) + +Alternatively, you may want to deploy API Platform on a PaaS (Platform as a Service): + +* [Deploying the server application of API Platform on Heroku](heroku.md) +* [Deploying API Platform on Platform.sh (outdated)](https://platform.sh/blog/deploy-api-platform-on-platformsh) diff --git a/deployment/kubernetes.md b/deployment/kubernetes.md index 9ea33e1bd1a..6d17cd0fc26 100644 --- a/deployment/kubernetes.md +++ b/deployment/kubernetes.md @@ -7,6 +7,8 @@ and [Amazon Web Services](https://aws.amazon.com/eks/) provide managed Kubernete [The official API Platform distribution](../distribution/index.md) contains a built-in [Helm](https://helm.sh/) (the k8s package manager) chart to deploy in a wink on any of these platforms. +If you want to deploy API Platform on a local Kubernetes cluster, check out [our Minikube tutorial](minikube.md)! + ## Preparing Your Cluster and Your Local Machine 1. Create a Kubernetes cluster on your preferred Cloud provider or install Kubernetes locally on your servers