From 334e4898679a46748db676227fe281a69a5a3e33 Mon Sep 17 00:00:00 2001 From: Lincoln Nogueira Date: Thu, 8 Feb 2024 05:28:43 -0300 Subject: [PATCH] chore: improve docker-compose.dev (#2938) --- scripts/docker-compose.dev.yaml | 375 +++++++++++++++++++++++++++----- 1 file changed, 320 insertions(+), 55 deletions(-) diff --git a/scripts/docker-compose.dev.yaml b/scripts/docker-compose.dev.yaml index b4035d7f..0806a7b4 100644 --- a/scripts/docker-compose.dev.yaml +++ b/scripts/docker-compose.dev.yaml @@ -1,74 +1,339 @@ +# > Memos development environment < +# +# Available profiles: sqlite, mysql, postgres. +# Use `docker compose --profile PROFILE_NAME up` to launch only services within the profile. +# +# Services in the `tools` profile are used for running one-off tasks like linting, generating code, etc. +# +# Services started in all database profiles: +# Front-end: http://localhost:3001 +# API: http://localhost:8081 +# Adminer: http://localhost:8091 +# +# On Windows, run this before using docker-compose on a new terminal: +# $Env:HOME=$Env:USERPROFILE +# +# > Start Memos in development mode: +# docker compose -f ./scripts/docker-compose.dev.yaml --profile [sqlite|mysql|postgres] up --detach +# +# > Stop all services: +# docker compose -f ./scripts/docker-compose.dev.yaml --profile sqlite --profile postgres --profile mysql down +# +# > Remove related volumes: (all other files are mapped to ./air/docker/ directory) +# docker volume rm memos-dev_pnpm-store memos-dev_node-modules +# +# One-off tasks: +# > pnpm: +# docker compose -f ./scripts/docker-compose.dev.yaml run --rm pnpm [add|remove|update] [PACKAGE_NAME] [--save-dev] +# +# > buf: (run this after modifying .proto files) +# docker compose -f ./scripts/docker-compose.dev.yaml run --rm buf generate +# +# > go: +# docker compose -f ./scripts/docker-compose.dev.yaml run --rm go mod tidy -go=1.22 +# +# > golangci-lint: (run this before submitting Pull Requests affecting Go code) +# docker compose -f ./scripts/docker-compose.dev.yaml run --rm golangci-lint run +# +# > goimports: (run this if golangci-lint shows "File is not `goimports`-ed" +# docker compose -f ./scripts/docker-compose.dev.yaml run --rm goimports -local https://github.com/usememos/memos -w [FILE|.] +# version: "3.0" name: memos-dev +volumes: + # pnpm uses hard links and node_modules uses symlinks. + # Using volumes make things work properly on any host OS. + node-modules: + pnpm-store: services: - db: - image: mysql - volumes: - - ./../.air/mysql:/var/lib/mysql - environment: - MYSQL_ALLOW_EMPTY_PASSWORD: yes - MYSQL_DATABASE: memos - api: - image: cosmtrek/air - working_dir: /work - command: ["-c", "./scripts/.air.toml"] - environment: - - "MEMOS_DSN=root@tcp(db)/memos" - - "MEMOS_DRIVER=mysql" - volumes: - - ./..:/work/ - - ./../.air/go-build:/root/.cache/go-build - - $HOME/go/pkg/:/go/pkg/ # Cache for go mod shared with the host web: + profiles: ["sqlite", "mysql", "postgres"] image: node:20-alpine - working_dir: /work - depends_on: ["api"] - ports: ["3001:3001"] - environment: ["DEV_PROXY_SERVER=http://api:8081/"] + ports: [3001:3001] + environment: + DEV_PROXY_SERVER: http://api:8081/ + NPM_CONFIG_UPDATE_NOTIFIER: false + working_dir: &web-working-dir /work/web entrypoint: ["/bin/sh", "-c"] command: ["corepack enable && pnpm i --frozen-lockfile && pnpm dev"] - tmpfs: /work/node_modules/:exec # To avoid pnpm ERR_PNPM_LINKING_FAILED error - volumes: - - ./../web:/work + tmpfs: &web-tmpfs /work/node_modules/:exec # avoid ERR_PNPM_LINKING_FAILED + volumes: &web-volumes + - node-modules:/work/web/node_modules + - pnpm-store:/work/web/.pnpm-store + - ../proto:/work/proto + - ../web:/work/web + healthcheck: + test: ["CMD", "wget", "-qO", "-", "http://localhost:3001"] + interval: 10s + timeout: 5s + + api: + profiles: ["sqlite"] + image: &api-image golang:1.22-alpine + ports: &api-ports [8081:8081] + environment: + MEMOS_DRIVER: sqlite + MEMOS_DATA: /var/opt/memos + working_dir: &api-working-dir /work + volumes: &api-volumes + - $HOME/go/pkg/:/go/pkg/ # Share go mod cache with host + - ../.air/docker/go-build:/root/.cache/go-build + - ../.air/docker/go/bin:/go/bin + - ../.air/docker/memosdata:/var/opt/memos + - ..:/work/ + configs: &api-configs + - source: air-entrypoint.sh + target: /usr/local/bin/entrypoint.sh + entrypoint: &api-entrypoint ["/bin/sh", "/usr/local/bin/entrypoint.sh"] + command: &api-command ["-c", "./scripts/.air.toml"] + healthcheck: &api-healthcheck + test: ["CMD", "wget", "-qO", "-", "http://localhost:8081/api/v1/ping"] + interval: 10s + timeout: 5s - # Services below are used for developers to run once - # - # You can just run `docker compose run --rm SERVICE_NAME` to use - # For example: - # To regenerate typescript code of gRPC proto - # Just run `docker compose run --rm buf` - # - # All of theses services belongs to profile 'tools' - # This will prevent to launch by normally `docker compose up` unexpectly + api-mysql: + profiles: ["mysql"] + depends_on: { mysql: { condition: service_healthy } } + hostname: api + environment: + { MEMOS_DRIVER: mysql, MEMOS_DSN: memos:memos@tcp(mysql)/memos } + image: *api-image + ports: *api-ports + working_dir: *api-working-dir + volumes: *api-volumes + configs: *api-configs + entrypoint: *api-entrypoint + command: *api-command + healthcheck: *api-healthcheck + + api-postgres: + profiles: ["postgres"] + depends_on: { postgres: { condition: service_healthy } } + hostname: api + environment: + MEMOS_DSN: "postgresql://memos:memos@postgres:5432/memos?sslmode=disable" + MEMOS_DRIVER: postgres + image: *api-image + ports: *api-ports + working_dir: *api-working-dir + volumes: *api-volumes + configs: *api-configs + entrypoint: *api-entrypoint + command: *api-command + healthcheck: *api-healthcheck + + mysql: + profiles: ["mysql"] + image: mysql + environment: + MYSQL_USER: memos + MYSQL_PASSWORD: memos + MYSQL_DATABASE: memos + MYSQL_ALLOW_EMPTY_PASSWORD: "yes" + volumes: [../.air/docker/mysql:/var/lib/mysql] + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] + interval: 10s + timeout: 5s + + postgres: + profiles: ["postgres"] + image: postgres:alpine + hostname: postgres + volumes: [../.air/docker/postgres:/var/lib/postgresql/data] + environment: + { POSTGRES_DB: memos, POSTGRES_USER: memos, POSTGRES_PASSWORD: memos } + healthcheck: + test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"] + interval: 10s + timeout: 5s + + pnpm: + profiles: ["tools"] + image: node:20-alpine + environment: { NPM_CONFIG_UPDATE_NOTIFIER: false } + working_dir: *web-working-dir + volumes: *web-volumes + tmpfs: *web-tmpfs + configs: + - source: pnpm-entrypoint.sh + target: /usr/local/bin/entrypoint.sh + entrypoint: ["sh", "/usr/local/bin/entrypoint.sh"] - # Generate typescript code of gRPC proto buf: profiles: ["tools"] image: bufbuild/buf working_dir: /work/proto command: generate volumes: - - ./../proto:/work/proto - - ./../web/src/types/:/work/web/src/types/ + - ../proto:/work/proto + - ../web/src/types/:/work/web/src/types/ - # Do golang static code check before create PR - golangci-lint: + go: profiles: ["tools"] - image: golangci/golangci-lint:v1.54.2 - working_dir: /work/ - entrypoint: golangci-lint - command: run -v - volumes: - - $HOME/go/pkg/:/go/pkg/ # Cache for go mod shared with the host - - ./../.air/go-build:/root/.cache/go-build - - ./..:/work/ + image: *api-image + working_dir: *api-working-dir + volumes: *api-volumes + entrypoint: ["go"] - # run npm - npm: + goimports: profiles: ["tools"] - image: node:20-alpine - working_dir: /work - environment: ["NPM_CONFIG_UPDATE_NOTIFIER=false"] - entrypoint: "npm" - volumes: - - ./../web:/work + image: *api-image + working_dir: *api-working-dir + volumes: *api-volumes + configs: + - source: goimports-entrypoint.sh + target: /usr/local/bin/entrypoint.sh + entrypoint: ["/bin/sh", "/usr/local/bin/entrypoint.sh"] + + golangci-lint: + profiles: ["tools"] + image: *api-image + working_dir: *api-working-dir + volumes: *api-volumes + configs: + - source: golangci-lint-entrypoint.sh + target: /usr/local/bin/entrypoint.sh + entrypoint: ["/bin/sh", "/usr/local/bin/entrypoint.sh"] + + adminer-mysql: + profiles: ["mysql"] + depends_on: { mysql: { condition: service_healthy } } + image: adminer + environment: &adminer-environment + ADMINER_DEFAULT_DRIVER: server # "server" is mysql + ADMINER_DEFAULT_SERVER: mysql + ADMINER_DEFAULT_USERNAME: memos + ADMINER_DEFAULT_PASSWORD: memos + ADMINER_DEFAULT_DB: memos + ADMINER_DESIGN: dracula # light: pepa-linha | https://www.adminer.org/#extras + ADMINER_PLUGINS: tables-filter table-structure edit-textarea dump-json # https://www.adminer.org/en/plugins/ + ports: &adminer-ports [127.0.0.1:8091:8080] + healthcheck: &adminer-healthcheck + test: 'php -r "exit(strpos(file_get_contents(\"http://localhost:8080/\"), \"Adminer\") !== false ? 0 : 1);"' + interval: 10s + timeout: 5s + configs: &adminer-configs + - source: adminer-index.php + target: /var/www/html/index.php + + adminer-postgres: + profiles: ["postgres"] + depends_on: { postgres: { condition: service_healthy } } + image: adminer + ports: *adminer-ports + healthcheck: *adminer-healthcheck + configs: *adminer-configs + environment: + <<: *adminer-environment + ADMINER_DEFAULT_DRIVER: pgsql + ADMINER_DEFAULT_SERVER: postgres + + adminer-sqlite: + profiles: ["sqlite"] + image: adminer + ports: *adminer-ports + healthcheck: *adminer-healthcheck + configs: *adminer-configs + environment: + <<: *adminer-environment + ADMINER_DEFAULT_PASSWORD: "" + ADMINER_DEFAULT_DRIVER: sqlite + ADMINER_DEFAULT_DB: /data/memos_dev.db + volumes: [../.air/docker/memosdata:/data] + +configs: + # Patched version of adminer index.php to fill the login form with default values + # and allow passwordless login whenever ADMINER_DEFAULT_DRIVER is sqlite. + adminer-index.php: + content: | +