diff --git a/deployment/images/deploy-result.png b/deployment/images/deploy-result.png new file mode 100644 index 00000000000..550f4d993a7 Binary files /dev/null and b/deployment/images/deploy-result.png differ diff --git a/deployment/images/google-image-caddy-details.png b/deployment/images/google-image-caddy-details.png new file mode 100644 index 00000000000..b661df45308 Binary files /dev/null and b/deployment/images/google-image-caddy-details.png differ diff --git a/deployment/images/google-image-overview.png b/deployment/images/google-image-overview.png new file mode 100644 index 00000000000..0f9b354fdfa Binary files /dev/null and b/deployment/images/google-image-overview.png differ diff --git a/deployment/kubernetes.md b/deployment/kubernetes.md index 6d17cd0fc26..fd560e687c3 100644 --- a/deployment/kubernetes.md +++ b/deployment/kubernetes.md @@ -1,103 +1,171 @@ # Deploying to a Kubernetes Cluster [Kubernetes](https://kubernetes.io/) has become the most popular way to deploy, run and manage containers in production. -Both [Google Cloud Platform](https://cloud.google.com/kubernetes-engine/), [Microsoft Azure](https://azure.microsoft.com/en-us/services/container-service/kubernetes/) -and [Amazon Web Services](https://aws.amazon.com/eks/) provide managed Kubernetes environment. +[Google Cloud Platform](https://cloud.google.com/kubernetes-engine/), [Microsoft Azure](https://azure.microsoft.com/en-us/services/container-service/kubernetes/) +and [Amazon Web Services](https://aws.amazon.com/eks/) and many more companies provide managed Kubernetes environment. [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. +This guide is based on Helm 3. + 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 -2. Install [Helm](https://helm.sh/) locally and on your cluster following their documentation -3. Be sure to be connected to the right Kubernetes container e.g. running: `gcloud config get-value core/project` -4. Update the Helm repo: `helm repo update` +1. Create a Kubernetes cluster on your preferred Cloud provider or install Kubernetes locally on your server, for example with [kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/) +2. Install [Helm 3](https://helm.sh/) `locally` following their [documentation](https://helm.sh/docs/intro/install/) +3. Be sure to be connected to the right Kubernetes cluster + `kubectl config view` [Details](https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/) + e.g. for Google Cloud running: `gcloud config get-value core/project` + +Working-Dir: Your local installation of api-platform. Default /api-platform/ ## Creating and Publishing the Docker Images -1. Build the PHP and NGINX Docker images: +### Example with the [Google Container Registry](https://cloud.google.com/container-registry/) and [Google Cloud Platform](https://cloud.google.com/kubernetes-engine/) + +Change the name "test-api-platform" to your Google project ID (not the project name). +[Quickstart Google Cloud](https://cloud.google.com/sdk/docs/quickstart?hl=de) +If you do not have gcloud yet, install it with these command. + + curl https://sdk.cloud.google.com | bash + +#### 1. Build the PHP and Caddy Docker images and tag them + +Versioning: The 0.1.0 is the version. This value should be the same as the attribute `appVersion` in `Chart.yaml`. +Infos for [Google Container pulling and pushing](https://cloud.google.com/container-registry/docs/pushing-and-pulling) + + docker build -t gcr.io/test-api-platform/php:0.1.0 -t gcr.io/test-api-platform/php:latest api --target api_platform_php + docker build -t gcr.io/test-api-platform/caddy:0.1.0 -t gcr.io/test-api-platform/caddy:latest api --target api_platform_caddy + docker build -t gcr.io/test-api-platform/pwa:0.1.0 -t gcr.io/test-api-platform/pwa:latest pwa --target api_platform_pwa_prod + +#### 2. Push your images to your Docker registry + + gcloud auth configure-docker + docker push gcr.io/test-api-platform/php + docker push gcr.io/test-api-platform/caddy + docker push gcr.io/test-api-platform/pwa + +Optional push the version images: + + docker push gcr.io/test-api-platform/php:0.1.0 + docker push gcr.io/test-api-platform/caddy:0.1.0 + docker push gcr.io/test-api-platform/pwa:0.1.0 - docker build -t gcr.io/test-api-platform/php -t gcr.io/test-api-platform/php:latest api --target api_platform_php - docker build -t gcr.io/test-api-platform/nginx -t gcr.io/test-api-platform/nginx:latest api --target api_platform_nginx - docker build -t gcr.io/test-api-platform/varnish -t gcr.io/test-api-platform/varnish:latest api --target api_platform_varnish +The result should look similar to these images. -2. Push your images to your Docker registry, example with [Google Container Registry](https://cloud.google.com/container-registry/): +![Example of Google Images - Overview](images/google-image-overview.png) +![Example of Google Caddy Image - Details](images/google-image-caddy-details.png) - Docker client versions <= 18.03: +## Deploying with Helm 3 - gcloud docker -- push gcr.io/test-api-platform/php - gcloud docker -- push gcr.io/test-api-platform/nginx - gcloud docker -- push gcr.io/test-api-platform/varnish +### 1. Check the Helm version - Docker client versions > 18.03: + helm version - gcloud auth configure-docker - docker push gcr.io/test-api-platform/php - docker push gcr.io/test-api-platform/nginx - docker push gcr.io/test-api-platform/varnish +If you are using version 2.x follow this [guide to migrate Helm to v3](https://helm.sh/docs/topics/v2_v3_migration/#helm) -## Deploying +### 2. Firstly you need to update helm dependencies by running -Firstly you need to update helm dependencies by running: + helm dependency update ./helm/api-platform - helm dependency update ./api/helm/api +This will create a folder helm/api-platform/charts/ and add all dependencies there. +Actual this is [bitnami/postgresql](https://bitnami.com/stack/postgresql/helm), a file postgresql-[VERSION].tgz is created. -You are now ready to deploy the API! +### 3. Optional: If you made changes to the Helm chart, check if its format is correct -Deploy your API to the container: + helm lint ./helm/api-platform - helm install ./api/helm/api --namespace=baz --name baz \ - --set php.repository=gcr.io/test-api-platform/php \ - --set nginx.repository=gcr.io/test-api-platform/nginx \ - --set secret=MyAppSecretKey \ - --set postgresql.postgresPassword=MyPgPassword \ +### 4. Deploy your API to the container + + helm upgrade main ./helm/api-platform --namespace=default --create-namespace --wait \ + --install \ + --set "php.image.repository=gcr.io/test-api-platform/php" \ + --set php.image.tag=latest \ + --set "caddy.image.repository=gcr.io/test-api-platform/caddy" \ + --set caddy.image.tag=latest \ + --set "pwa.image.repository=gcr.io/test-api-platform/pwa" \ + --set pwa.image.tag=latest \ + --set php.appSecret='!ChangeMe!' \ + --set postgresql.postgresqlPassword='!ChangeMe!' \ --set postgresql.persistence.enabled=true \ - --set corsAllowOrigin='^https?://[a-z\]*\.mywebsite.com$' + --set "corsAllowOrigin=^https?:\/\/[a-z]*\.mywebsite.com$" + +The `"` are necessary for Windows. Use ^ on Windows instead of \ to split commands into multiple lines. +You can add the parameter `--dry-run` to check upfront if anything is correct. +Replace the values with the image parameters from the stage above. +The parameter `php.appSecret` is the `AppSecret` from ./.env +Fill the rest of the values with the correct settings. +For available options see /helm/api-platform/values.yaml. +If you want a test deploy you can set corsAllowOrigin='*' + +After a successful installation, there is a message at the end. +You can copy these commands and execute them to set a port-forwarding and +get access on your local machine to the deploy. See image below. + +![Deploy Result](images/deploy-result.png) If you prefer to use a managed DBMS like [Heroku Postgres](https://www.heroku.com/postgres) or [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/) (recommended): - helm install --name api ./api/helm/api \ + helm upgrade api-platform ./helm/api-platform \ # ... --set postgresql.enabled=false \ - --set postgresql.url=pgsql://username:password@host/database?serverVersion=9.6 + --set postgresql.url=pgsql://username:password@host/database?serverVersion=13 + +Finally, build the `pwa` (client and admin) JavaScript apps and [deploy them on a static +website hosting service](https://create-react-app.dev/docs/deployment/). -If you want to use a managed Varnish such as [Fastly](https://www.fastly.com) for the invalidation cache mechanism -provided by API Platform: +## Access the container - helm install --name api ./api/helm/api \ - # ... - --set varnish.enabled=false \ - --set varnish.url=https://myvarnish.com +You can access the php container of the pod with the following command. +In this example the symfony console is called. -Finally, build the `client` and `admin` JavaScript apps and [deploy them on a static -website hosting service](https://create-react-app.dev/docs/deployment/). + CADDY_PHP_POD=$(kubectl --namespace=default get pods -l app.kubernetes.io/name=api-platform -o jsonpath="{.items[0].metadata.name}") + kubectl --namespace=default exec -it $CADDY_PHP_POD -c api-platform-php -- bin/console + +## Caution for system architecture + +If the pods do not run, and you get the following error from google kubernetes engine logs, +there is probably a problem with the system architecture. +`standard_init_linux.go:211: exec user process caused "exec format error` +Build the images with the same system architecture as the cluster runs. +Example: Building with Mac M1 with arm64 leads to problems. Most cluster will run with x86_64. +Solution: -## Initializing the Database +## Updates -Before running your application for the first time, be sure to create the database schema: +There are 2 main upgrade strategies. - PHP_POD=$(kubectl --namespace=bar get pods -l app=php -o jsonpath="{.items[0].metadata.name}") - kubectl --namespace=bar exec -it $PHP_POD -- bin/console doctrine:schema:create +### 1. Always version your images (recommended) -## Tiller RBAC Issue +Change the version in the attribut "appVersion" in Chart.yaml and tag the images with this version. +You can upgrade with the same command from the installation and pass all parameters. -We noticed that some tiller RBAC trouble occurred. You can usually resolve it by running: +### 2. Use :latest tags - kubectl create serviceaccount --namespace kube-system tiller - serviceaccount "tiller" created +Infos about [best practices for tagging images for kubernetes](https://kubernetes.io/docs/concepts/containers/images/) +You have to use the *.image.pullPolicy=Always see the last 3 parameters. - kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller - clusterrolebinding "tiller-cluster-rule" created + helm upgrade api-platform ./helm/api-platform --namespace=default \ + --set "php.image.repository=gcr.io/test-api-platform/php" \ + --set php.image.tag=latest \ + --set "caddy.image.repository=gcr.io/test-api-platform/caddy" \ + --set caddy.image.tag=latest \ + --set "pwa.image.repository=gcr.io/test-api-platform/pwa" \ + --set pwa.image.tag=latest \ + --set php.appSecret='!ChangeMe!' \ + --set postgresql.postgresqlPassword='!ChangeMe!' \ + --set postgresql.persistence.enabled=true \ + --set "corsAllowOrigin=^https?://[a-z\]*\.mywebsite.com$" \ + --set php.image.pullPolicy=Always \ + --set caddy.image.pullPolicy=Always \ + --set pwa.image.pullPolicy=Always - kubectl patch deploy --namespace kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}' - deployment "tiller-deploy" patched +## GitHub Actions Example for deployment -Please, see the [related issue](https://github.com/kubernetes/helm/issues/3130) for further details / information. -You can also take a look at the [related documentation](https://github.com/kubernetes/helm/blob/master/docs/rbac.md) +You can find a [complete deploy command for GKE](https://github.com/api-platform/demo/blob/main/.github/workflows/deploy.yml) on the [demo project](https://github.com/api-platform/demo/): ## Symfony Messenger