From 175d90b14746ee8ce64698741a41cf2472586b7b Mon Sep 17 00:00:00 2001 From: Paul Pan Date: Sat, 15 Jul 2023 18:14:50 +0800 Subject: [PATCH] feat: initial docker support --- .gitignore | 98 +------------------------------------------- Dockerfile | 31 ++++++++++++++ config.docker.yaml | 35 ++++++++++++++++ config.yaml | 35 ---------------- docker-compose.yml | 86 ++++++++++++++++++++++++++++++++++++++ docker-entrypoint.sh | 84 +++++++++++++++++++++++++++++++++++++ 6 files changed, 238 insertions(+), 131 deletions(-) create mode 100644 Dockerfile create mode 100644 config.docker.yaml delete mode 100644 config.yaml create mode 100644 docker-compose.yml create mode 100755 docker-entrypoint.sh diff --git a/.gitignore b/.gitignore index 8826357..90f2116 100644 --- a/.gitignore +++ b/.gitignore @@ -1,96 +1,2 @@ -### Project -/tmp -/server -/runner -my.secrets - -### JetBrains template -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff -.idea/**/workspace.xml -.idea/**/tasks.xml -.idea/**/usage.statistics.xml -.idea/**/dictionaries -.idea/**/shelf - -# Generated files -.idea/**/contentModel.xml - -# Sensitive or high-churn files -.idea/**/dataSources/ -.idea/**/dataSources.ids -.idea/**/dataSources.local.xml -.idea/**/sqlDataSources.xml -.idea/**/dynamic.xml -.idea/**/uiDesigner.xml -.idea/**/dbnavigator.xml - -# Gradle -.idea/**/gradle.xml -.idea/**/libraries - -# Gradle and Maven with auto-import -# When using Gradle or Maven with auto-import, you should exclude module files, -# since they will be recreated, and may cause churn. Uncomment if using -# auto-import. -# .idea/artifacts -# .idea/compiler.xml -# .idea/jarRepositories.xml -# .idea/modules.xml -# .idea/*.iml -# .idea/modules -# *.iml -# *.ipr - -# CMake -cmake-build-*/ - -# Mongo Explorer plugin -.idea/**/mongoSettings.xml - -# File-based project format -*.iws - -# IntelliJ -out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Cursive Clojure plugin -.idea/replstate.xml - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties - -# Editor-based Rest Client -.idea/httpRequests - -# Android studio 3.1+ serialized cache file -.idea/caches/build_file_checksums.ser - -### Go template -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll -*.so -*.dylib - -# Test binary, built with `go test -c` -*.test - -# Output of the go coverage tool, specifically when used with LiteIDE -*.out - -# Dependency directories (remove the comment below to include it) -# vendor/ - +/woj +/config.yaml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..71692e5 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,31 @@ +# builder +FROM golang:alpine AS builder + +ENV GOPROXY=https://goproxy.cn +WORKDIR /builder + +RUN apk add --no-cache git make +RUN go install github.com/swaggo/swag/cmd/swag@latest + +COPY go.mod /builder/go.mod +COPY go.sum /builder/go.sum +RUN go mod download + +COPY . /builder +RUN make build + + +# main image +FROM alpine:latest + +WORKDIR /app +RUN apk --no-cache add tzdata ca-certificates libc6-compat + +COPY --from=builder /builder/config.docker.yaml /app +COPY --from=builder /builder/docker-entrypoint.sh /app +COPY --from=builder /builder/resource/frontend /app/resource/frontend +COPY --from=builder /builder/resource/runner /app/resource/runner + +COPY --from=builder /builder/woj /app + +ENTRYPOINT ["/app/docker-entrypoint.sh"] diff --git a/config.docker.yaml b/config.docker.yaml new file mode 100644 index 0000000..9369611 --- /dev/null +++ b/config.docker.yaml @@ -0,0 +1,35 @@ +WebServer: + Address: ${WEB_SERVER_ADDRESS} + Port: ${WEB_SERVER_PORT} + JwtSigningKey: ${WEB_SERVER_JWT_SIGNING_KEY} + JwtExpireHour: ${WEB_SERVER_JWT_EXPIRE_HOUR} + +Redis: + Db: ${REDIS_DB} + QueueDb: ${REDIS_QUEUE_DB} + Address: ${REDIS_ADDRESS_PORT} + Password: ${REDIS_PASSWORD} + +Database: + Host: ${DATABASE_HOST} + Port: ${DATABASE_PORT} + User: ${DATABASE_USER} + Password: ${DATABASE_PASSWORD} + Database: ${DATABASE_NAME} + Prefix: ${DATABASE_PREFIX} + MaxOpenConns: ${DATABASE_MAX_OPEN_CONNS} + MaxIdleConns: ${DATABASE_MAX_IDLE_CONNS} + ConnMaxLifetime: ${DATABASE_CONN_MAX_LIFETIME} + +Storage: + Endpoint: ${STORAGE_ENDPOINT} + UseSSL: ${STORAGE_USE_SSL} + AccessKey: ${STORAGE_ACCESS_KEY} + SecretKey: ${STORAGE_SECRET_KEY} + Bucket: ${STORAGE_BUCKET} + +Metrics: + Namespace: ${METRICS_NAMESPACE} + Subsystem: ${METRICS_SUBSYSTEM} + +Development: ${DEVELOPMENT} diff --git a/config.yaml b/config.yaml deleted file mode 100644 index 206536b..0000000 --- a/config.yaml +++ /dev/null @@ -1,35 +0,0 @@ -WebServer: - Address: 0.0.0.0 - Port: 8000 - JwtSigningKey: 'rq67SdQIRABhHq40' - JwtExpireHour: 12 - -Redis: - Db: 0 - QueueDb: 1 - Address: '127.0.0.1:6379' - Password: '' - -Database: - Host: '127.0.0.1' - Port: 5432 - User: 'dev' - Password: 'password' - Database: 'dev' - Prefix: 'oj_' - MaxOpenConns: 100 - MaxIdleConns: 60 - ConnMaxLifetime: 60 - -Storage: - Endpoint: '127.0.0.1:9000' - UseSSL: false - AccessKey: 'EHd5Zj56QrTivhFI' - SecretKey: 'FUHy4RW1mn0Kbr5pibDZ6R2F9116FZKY' - Bucket: 'woj' - -Metrics: - Namespace: 'OJ' - Subsystem: 'server' - -Development: true diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..96c4cd7 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,86 @@ +version: "3" + +services: + server: + build: . + restart: unless-stopped + command: web + environment: + - REDIS_ADDRESS_PORT=cache:6379 + - DATABASE_HOST=db + - DATABASE_USER=dev + - DATABASE_PASSWORD=password + - DATABASE_NAME=dev + - STORAGE_ENDPOINT=minio:9000 + - STORAGE_ACCESS_KEY=access_key + - STORAGE_SECRET_KEY=secret_key + - STORAGE_BUCKET=woj + - DEVELOPMENT=true + volumes: + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + depends_on: + storage: + condition: service_healthy + cache: + condition: service_healthy + db: + condition: service_healthy + ports: + - "8000:8000" + + #runner: + # build: . + # restart: unless-stopped + # command: runner + # environment: + # - REDIS_ADDRESS_PORT=cache:6379 + # - DEVELOPMENT=true + # volumes: + # - runner:/app/resource/runner/user + # - /etc/timezone:/etc/timezone:ro + # - /etc/localtime:/etc/localtime:ro + # depends_on: + # - cache + + storage: + image: minio/minio:latest + restart: unless-stopped + healthcheck: + test: [ "CMD", "echo", "ok" ] + interval: 5s + entrypoint: sh + command: -c 'mkdir -p /data/woj && minio server /data' + environment: + MINIO_ACCESS_KEY: "access_key" + MINIO_SECRET_KEY: "secret_key" + volumes: + - storage:/data + + cache: + image: redis:alpine + restart: unless-stopped + healthcheck: + test: [ "CMD", "redis-cli", "ping" ] + interval: 5s + volumes: + - cache:/data + + db: + image: postgres:alpine + restart: unless-stopped + healthcheck: + test: [ "CMD", "pg_isready", "-U", "dev" ] + interval: 5s + environment: + - POSTGRES_USER=dev + - POSTGRES_PASSWORD=password + - POSTGRES_DB=dev + volumes: + - db:/var/lib/postgresql/data + +volumes: + runner: + storage: + cache: + db: \ No newline at end of file diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100755 index 0000000..4728bdd --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,84 @@ +#!/bin/ash +set -eo pipefail + +COLOR_RED="\e[0;31m" +COLOR_GREEN="\e[0;32m" +COLOR_YELLOW="\e[0;33m" +COLOR_NONE="\e[0m" +function log_info() { echo -e "${COLOR_GREEN}$*${COLOR_NONE}" 1>&2; } +function log_warn() { echo -e "${COLOR_YELLOW}$*${COLOR_NONE}" 1>&2; } +function log_error() { echo -e "${COLOR_RED}$*${COLOR_NONE}" 1>&2; } + +log_info "extracting env vars" + +function check_env() { + # $1 -> var name + # $2 -> default value + # $3 -> quota or not + val=$(eval "echo -n \${$1}") + if test -z "$val"; then + log_warn "Environment variable $1 is not set, using default value \"$2\"" + export "$1"="$2" + else + log_info "Using $1=$val" + fi + + if "$3"; then + val=$(eval "echo -n \${$1}") + # shellcheck disable=SC2140 + export "$1"="'$val'" + fi + + # echo -n ">>>>> " + # eval "echo -n \${$1}" + # echo " <<<<<" +} + +check_env "WEB_SERVER_ADDRESS" "0.0.0.0" true +check_env "WEB_SERVER_PORT" 8000 false +check_env "WEB_SERVER_JWT_SIGNING_KEY" "$(head -n 10 /dev/urandom | md5sum | cut -c 1-32)" true +check_env "WEB_SERVER_JWT_EXPIRE_HOUR" 12 false + +check_env "REDIS_DB" 0 false +check_env "REDIS_QUEUE_DB" 1 false +check_env "REDIS_ADDRESS_PORT" "redis:6379" true +check_env "REDIS_PASSWORD" "" true + +check_env "DATABASE_HOST" "postgres" true +check_env "DATABASE_PORT" 5432 false +check_env "DATABASE_USER" "dev" true +check_env "DATABASE_PASSWORD" "password" true +check_env "DATABASE_NAME" "dev" true +check_env "DATABASE_PREFIX" "oj_" true +check_env "DATABASE_MAX_OPEN_CONNS" 100 false +check_env "DATABASE_MAX_IDLE_CONNS" 60 false +check_env "DATABASE_CONN_MAX_LIFETIME" 60 false + +check_env "STORAGE_ENDPOINT" "minio:9000" true +check_env "STORAGE_USE_SSL" "false" false +check_env "STORAGE_ACCESS_KEY" "access_key" true +check_env "STORAGE_SECRET_KEY" "secret_key" true +check_env "STORAGE_BUCKET" "woj" true + +check_env "METRICS_NAMESPACE" "woj" true +check_env "METRICS_SUBSYSTEM" "server" true + +check_env "DEVELOPMENT" false false + +rm -f /tmp/tmp.yaml +( + echo "cat </app/config.yaml" + cat /app/config.docker.yaml + echo "EOF" +) >/tmp/tmp.yaml + +if [ -f '/app/config.yaml' ]; then + log_info "config.yaml already exists, skip" +else + log_info "creating config.yaml" + . /tmp/tmp.yaml || (log_error "failed to create config.yaml" && exit 1) +fi + +log_info "starting woj" +#cat /app/config.yaml +exec /app/woj "$@"