From 9a374f9c5ce92c7e202e18be6494f80b200f9a8c Mon Sep 17 00:00:00 2001 From: Silvan Date: Fri, 31 Dec 2021 18:04:20 +0100 Subject: [PATCH] refactor(local): docker compose (#2892) * refactor(local): docker compose * fix(compose): disable logging in gateway * docs: guide for local development * docs(local): quickstart * docs: resources * use docker-compose dns * Apply suggestions from code review Co-authored-by: Florian Forster Co-authored-by: Elio Bischof Co-authored-by: Florian Forster --- build/local/Dockerfile.gateway | 3 - build/local/Dockerfile.started | 10 -- build/local/docker-compose-local.yml | 157 ++++++++++++++++----------- build/local/zitadel-started.sh | 57 ---------- guides/development.md | 44 ++++---- guides/quickstart.md | 55 ++++++---- 6 files changed, 150 insertions(+), 176 deletions(-) delete mode 100644 build/local/Dockerfile.started delete mode 100755 build/local/zitadel-started.sh diff --git a/build/local/Dockerfile.gateway b/build/local/Dockerfile.gateway index 5483c93d94..4aef6d09d2 100644 --- a/build/local/Dockerfile.gateway +++ b/build/local/Dockerfile.gateway @@ -23,9 +23,6 @@ RUN dep ensure && \ go env -w GO111MODULE=auto && \ go install ./go/grpcwebproxy -# ADD ./etc/localhost.crt /etc -# ADD ./etc/localhost.key /etc - ENV BKD_HOST=backend-run ENV BKD_PORT=50001 diff --git a/build/local/Dockerfile.started b/build/local/Dockerfile.started deleted file mode 100644 index 60bf416445..0000000000 --- a/build/local/Dockerfile.started +++ /dev/null @@ -1,10 +0,0 @@ -FROM ubuntu:latest AS started -#install dependencies with a workaround for the 412 error -RUN apt-get update \ - && apt-get install curl -y - -#prepare script -COPY build/local/zitadel-started.sh zitadel-started.sh -RUN chmod +x /zitadel-started.sh - -ENTRYPOINT [ "/zitadel-started.sh" ] diff --git a/build/local/docker-compose-local.yml b/build/local/docker-compose-local.yml index 9121eb6727..a56c0bab50 100644 --- a/build/local/docker-compose-local.yml +++ b/build/local/docker-compose-local.yml @@ -2,18 +2,47 @@ version: '3.8' services: db: - profiles: ['database'] + profiles: ['backend', 'storage'] restart: always networks: - zitadel image: cockroachdb/cockroach:v21.2.3 command: start-single-node --insecure --listen-addr=0.0.0.0 + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8080/health?ready=1"] + interval: 10s + timeout: 30s + retries: 5 + start_period: 20s ports: - 8080:8080 - 26257:26257 +# schema changes on the database + db-migrations: + profiles: ['backend', 'storage'] + restart: on-failure + networks: + - zitadel + depends_on: + db: + condition: service_healthy + image: flyway/flyway:latest + volumes: + - ../../migrations/cockroach:/flyway/sql + environment: + - FLYWAY_PLACEHOLDERS_eventstorepassword=NULL + - FLYWAY_PLACEHOLDERS_managementpassword=NULL + - FLYWAY_PLACEHOLDERS_adminapipassword=NULL + - FLYWAY_PLACEHOLDERS_authpassword=NULL + - FLYWAY_PLACEHOLDERS_notificationpassword=NULL + - FLYWAY_PLACEHOLDERS_authzpassword=NULL + - FLYWAY_PLACEHOLDERS_queriespassword=NULL + command: -url=jdbc:postgresql://db:26257/defaultdb -user=root -password= -connectRetries=5 migrate + +# minio is used to store assets minio: - profiles: ['backend'] + profiles: ['backend', 'storage'] image: minio/minio:RELEASE.2021-06-14T01-29-23Z restart: on-failure networks: @@ -32,28 +61,11 @@ services: - nas - /export - db-migrations: - profiles: ['database'] - restart: on-failure - networks: - - zitadel - depends_on: - - db - image: flyway/flyway:latest - volumes: - - ../../migrations/cockroach:/flyway/sql - environment: - - FLYWAY_PLACEHOLDERS_eventstorepassword=NULL - - FLYWAY_PLACEHOLDERS_managementpassword=NULL - - FLYWAY_PLACEHOLDERS_adminapipassword=NULL - - FLYWAY_PLACEHOLDERS_authpassword=NULL - - FLYWAY_PLACEHOLDERS_notificationpassword=NULL - - FLYWAY_PLACEHOLDERS_authzpassword=NULL - - FLYWAY_PLACEHOLDERS_queriespassword=NULL - command: -url=jdbc:postgresql://db:26257/defaultdb -user=root -password= -connectRetries=5 migrate - +# ZITADEL needs several keys to encrypt data +# this container generates the required keys +# and stores them into zitadel/.keys keys: - profiles: ['init-backend'] + profiles: ['backend', 'backend-stub'] restart: on-failure networks: - zitadel @@ -66,13 +78,20 @@ services: env_file: - ./local.env +# To interact with ZITADEL requires some data setted up. +# Due to the evolution of ZITADEL it's required to add additional +# setup steps, because of this fact it's recommended to rerun the setup +# on each restart, at least after a new version got released backend-setup: - profiles: ['init-backend'] + profiles: ['backend'] restart: on-failure networks: - zitadel depends_on: - - keys + db-migrations: + condition: service_completed_successfully + keys: + condition: service_completed_successfully build: context: ../.. dockerfile: build/zitadel/Dockerfile @@ -93,14 +112,28 @@ services: 'setup', ] +# starts the backend (API's) of ZITADEL +# Port 50001 serves the GRPC API +# Port 50002 serves the REST API +# Port 50003 serves the login GUI backend-run: profiles: ['backend'] restart: on-failure networks: - zitadel + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:50002/management/v1/healthz"] + interval: 10s + timeout: 30s + retries: 5 + start_period: 20s depends_on: - - db - - minio + db: + condition: service_healthy + minio: + condition: service_healthy + backend-setup: + condition: service_completed_successfully build: context: ../.. dockerfile: build/zitadel/Dockerfile @@ -114,6 +147,7 @@ services: environment: - ZITADEL_EVENTSTORE_HOST=db ports: + - 50001:50001 - 50002:50002 - 50003:50003 command: @@ -126,26 +160,17 @@ services: 'start', ] - zitadel-started-up: - profiles: ['setup'] - networks: - - zitadel - extra_hosts: - host.docker.internal: host-gateway - build: - context: ../.. - dockerfile: build/local/Dockerfile.started - volumes: - - ./environment.json:/environment.json - environment: - - BE_PORT=50002 - - FE_PORT=4200 - +# the GRPC web gateway proxies the +# GRPC web calls to GRPC +# it's used in console (frontend) for example grpc-web-gateway: - profiles: ['frontend'] + profiles: ['backend'] restart: on-failure logging: driver: none + depends_on: + backend-run: + condition: service_healthy networks: - zitadel build: @@ -154,16 +179,38 @@ services: image: grpcweb/grpcwebproxy ports: - '50000:8080' - environment: - - BKD_HOST=host.docker.internal - - BKD_PORT=50001 - frontend-local-run: +# this service generates the environemnt.json +# needed in console. +# It curl's the client id of console and writes it to +# the environment.json + client-id: + profiles: ['frontend', 'console-stub'] + depends_on: + backend-run: + condition: service_healthy + networks: + - zitadel + build: + context: ../.. + dockerfile: build/local/Dockerfile.clientid + target: client-id + volumes: + - ./environment.json:/environment.json + environment: + - HOST=backend-run + - PORT=50002 + +# starts console in development mode + frontend-run: profiles: ['frontend'] networks: - zitadel depends_on: - - grpc-web-gateway + grpc-web-gateway: + condition: service_started + client-id: + condition: service_completed_successfully build: context: ../.. dockerfile: build/console/Dockerfile @@ -176,19 +223,5 @@ services: ports: - 4200:4200 - client-id: - profiles: ['init-frontend'] - networks: - - zitadel - build: - context: ../.. - dockerfile: build/local/Dockerfile.clientid - target: client-id - volumes: - - ./environment.json:/environment.json - environment: - - HOST=host.docker.internal - - PORT=50002 - networks: zitadel: {} diff --git a/build/local/zitadel-started.sh b/build/local/zitadel-started.sh deleted file mode 100755 index 10f721d7e1..0000000000 --- a/build/local/zitadel-started.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/bash - -# ------------------------------ -# prints a message as soon as -# ZITADEL is ready -# ------------------------------ - -be_status="" -env_status="" -console_status="" - -while [[ $be_status != 200 && $env_status != 200 ]]; do - sleep 5 - ## This is a workaround for a race condition - if [[ $be_status -eq 412 ]]; then - echo "please restart the process once again to get rid of the 412 error!" - fi - be_status=$(curl -s -o /dev/null -I -w "%{http_code}" host.docker.internal:${BE_PORT}/clientID) - env_status=$(curl -s -o /dev/null -I -w "%{http_code}" host.docker.internal:${FE_PORT}/assets/environment.json) - echo "backend (${be_status}) or environment (${env_status}) not ready yet ==> retrying in 5 seconds" -done - -echo "backend and environment.json ready!" - -while [[ $console_status != 200 ]]; do - sleep 15 - console_status=$(curl -s -o /dev/null -I -w "%{http_code}" host.docker.internal:${FE_PORT}/index.html) - echo "console (${console_status}) not ready yet ==> retrying in 15 seconds" -done - -echo "console ready - please wait shortly!" -sleep 15 - -echo -e "++=======================================================================================++ -|| || -|| ZZZZZZZZZZZZ II TTTTTTTTTTTT AAAA DDDDDD EEEEEEEEEE LL || -|| ZZ II TT AA AA DD DD EE LL || -|| ZZ II TT AA AA DD DD EE LL || -|| ZZ II TT AA AA DD DD EEEEEEEE LL || -|| ZZ II TT AAAAAAAAAAAA DD DD EE LL || -|| ZZ II TT AA AA DD DD EE LL || -|| ZZZZZZZZZZZZ II TT AA AA DDDDDD EEEEEEEEEE LLLLLLLLLL || -|| || -|| || -|| SSSSSSSSSS TTTTTTTTTTTT AAAA RRRRRRRR TTTTTTTTTTTT EEEEEEEEEE DDDDDD || -|| SS TT AA AA RR RR TT EE DD DD || -|| SS TT AA AA RR RR TT EE DD DD || -|| SSSSSS TT AA AA RRRRRRRR TT EEEEEEEE DD DD || -|| SS TT AAAAAAAAAAAA RRRR TT EE DD DD || -|| SS TT AA AA RR RR TT EE DD DD || -|| SSSSSSSSSS TT AA AA RR RR TT EEEEEEEEEE DDDDDD || -|| || -++=======================================================================================++" - -echo "access the console here http://localhost:${FE_PORT}" -echo "access the login here http://localhost:50003/login" -echo "access the apis here http://localhost:50002" diff --git a/guides/development.md b/guides/development.md index 293bd65e9c..a6d49798fa 100644 --- a/guides/development.md +++ b/guides/development.md @@ -6,6 +6,11 @@ You should stay in the ZITADEL root directory to execute the statements in the f - Buildkit compatible docker installation +Minimum resources: + +- CPU's: 2 +- Memory: 4Gb + ### env variables You can use the default vars provided in [this .env-file](../build/local/local.env) or create your own and update the paths in the [docker compose file](../build/local/docker-compose-local.yml). @@ -22,53 +27,46 @@ This command generates the grpc stub for console into the folder console/src/app DOCKER_BUILDKIT=1 docker build -f build/console/Dockerfile . -t zitadel:gen-fe --target npm-copy -o . ``` -### Backend +### Start the Backend -With this command you can generate the stub for the backend. +With these commands you can generate the stub for the backend. ```bash # generates grpc stub DOCKER_BUILDKIT=1 docker build -f build/zitadel/Dockerfile . -t zitadel:gen-be --target go-copy -o . # generates keys for cryptography -DOCKER_BUILDKIT=1 docker build --target copy-keys -f build/local/Dockerfile.keys . -o .keys +COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 \ +&& docker compose -f ./build/local/docker-compose-local.yml --profile backend-stub up --exit-code-from keys ``` ## Run -### Initialise data +### Start storage -Used if you want to setup the database and load the initial data. +Use this if you only want to start the storage services needed by ZITADEL. These services are started in background (detached). ```bash -COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker-compose -f ./build/local/docker-compose-local.yml --profile database --profile init-backend -p zitadel up +COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 \ +&& docker compose -f ./build/local/docker-compose-local.yml --profile storage up -d ``` -You can stop as soon as db-migrations AND backend-setup returned with exit code 0. +**On apple silicon:** +Restart the command (second terminal `docker restart zitadel__1`) if `db` logs `qemu: uncaught target signal 11 (Segmentation fault) - core dumped` or no logs are written from `db-migrations`. -### Initialise frontend +### Initialize the console Used to set the client id of the console. This step is for local development. If you don't work with a local backend you have to set the client id manually. You must [initialise the data](###-Initialise-data)) first. ```bash -COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker-compose -f ./build/local/docker-compose-local.yml --profile database --profile backend --profile init-frontend -p zitadel up --exit-code-from client-id +COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 \ +&& docker compose -f ./build/local/docker-compose-local.yml --profile console-stub up --exit-code-from client-id ``` The command exists as soon as the client id is set. -### Run database - -Used if you want to run the backend/console locally and only need the database. It's recommended to [initialise the data](###-Initialise-data) first. - -```bash -COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker-compose -f ./build/local/docker-compose-local.yml --profile database -p zitadel up -``` - -**On apple silicon:** -Restart the command (second terminal `docker restart zitadel__1`) if `db` logs `qemu: uncaught target signal 11 (Segmentation fault) - core dumped` or no logs are written from `db-migrations`. - -### Run Console +### Start the Console The console service is configured for hot reloading. You can also use docker compose for local development. @@ -79,7 +77,7 @@ If you use the local backend ensure that you have [set the correct client id](## #### Run console in docker compose ```bash -COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker-compose -f ./build/local/docker-compose-local.yml --profile frontend -p zitadel up +COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker compose -f ./build/local/docker-compose-local.yml --profile frontend up ``` ### Run backend @@ -89,7 +87,7 @@ Used if you want to run the backend locally. It's recommended to [initialise the #### Run backend in docker compose ```bash -COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker-compose -f ./build/local/docker-compose-local.yml --profile database --profile backend -p zitadel up +COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker compose -f ./build/local/docker-compose-local.yml --profile storage --profile backend up ``` #### Run backend locally diff --git a/guides/quickstart.md b/guides/quickstart.md index 6be2d06f61..01a4b25616 100644 --- a/guides/quickstart.md +++ b/guides/quickstart.md @@ -1,50 +1,63 @@ # Quickstart with docker compose +## Prerequisites + +The only prerequisite you need fullfill, is that you need to have docker installed with support for compose and buildkit. The resource limit must at least be: + +* CPU's: 2 +* Memory: 4Gb + +## Start ZITADEL + You can start ZITADEL with a simple docker compose up. The services are configured to restart if an error occurs. In the following script the basic setup of the database is executed before ZITADEL starts. Execute the statement from the root of ZITADEL. -You can connect to [ZITADEL on localhost:4200](http://localhost:4200) as soon as the following text appears: - -```text -++=========++ -|| ZITADEL || -|| STARTED || -++=========++ -``` +You can connect to [ZITADEL on localhost:4200](http://localhost:4200) after the frontend compiled successfully. Initially it takes several minutes to start all containers. ```bash COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 \ -&& docker-compose -f ./build/local/docker-compose-local.yml --profile database -p zitadel up --exit-code-from db-migrations \ -&& sleep 5 \ -&& docker-compose -f ./build/local/docker-compose-local.yml --profile database --profile init-backend --profile init-frontend --profile backend --profile frontend --profile setup -p zitadel up +&& docker compose -f ./build/local/docker-compose-local.yml --profile backend --profile frontend up ``` For a more detailed guide take a look at the [development guide](./development.md) ## FAQ +### Mac M1 (Apple Silicon) + +Bellow are some errors we faced with apple silicon. + +#### database-migrations don't start or stop without exit code + +You can simply restart the database with the following command: + +```bash +COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 \ +&& docker compose -f ./build/local/docker-compose-local.yml restart db +``` + +#### API call's block and don't return any response + +The problem is that the database has a connection issues. You can simply restart the database with the following command: + +```bash +COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 \ +&& docker compose -f ./build/local/docker-compose-local.yml restart db +``` + ### Build Errors If you experience strange docker error you might need to check that `buildkit` is enabled. Make sure to enable `"features": { "buildkit": true }` in your docker settings! -### Error 412 - -If the line `backend (412), environment (000) or console (000) not ready yet ==> retrying in 5 seconds` contains a `412` you struck a race condition within the start process (It should exit 1 when this happens). This will be fixed in a future release. You can work around it by restarting the containers. - -```Bash -COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 \ -docker-compose -f ./build/local/docker-compose-local.yml --profile database --profile init-backend --profile init-frontend --profile backend --profile frontend --profile setup -p zitadel up -``` - ### Remove the quickstart ```Bash -docker-compose -f ./build/local/docker-compose-local.yml --profile database --profile init-backend --profile init-frontend --profile backend --profile frontend --profile setup -p zitadel rm +docker-compose -f ./build/local/docker-compose-local.yml --profile database --profile init-backend --profile init-frontend --profile backend --profile frontend rm ``` If you are **confident** that you don't need to run the same ZITADEL instance again, go ahead and delete the `.keys` folder and reset the `environment.json` as well.