diff --git a/.gitignore b/.gitignore index 78888ec..37e138c 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,9 @@ docker-compose.override.yml # vendor vendor + +# Cover output +.cover + +# Local config +config.yml diff --git a/Dockerfile-dev b/Dockerfile-dev deleted file mode 100644 index 5f2f567..0000000 --- a/Dockerfile-dev +++ /dev/null @@ -1,23 +0,0 @@ -FROM golang:1.9-alpine - -RUN mkdir -p /go/src/elyby/minecraft-skinsystem \ - /go/src/elyby/minecraft-skinsystem/data/capes \ - && ln -s /go/src/elyby/minecraft-skinsystem /go/src/app - -WORKDIR /go/src/app - -COPY ./ /go/src/app/ - -RUN apk add --no-cache git \ - && go get -u github.com/golang/dep/cmd/dep \ - && dep ensure \ - && go clean -i github.com/golang/dep \ - && rm -rf $GOPATH/src/github.com/golang/dep \ - && apk del git \ - && go build main.go \ - && mv main /usr/local/bin/minecraft-skinsystem - -EXPOSE 80 - -ENTRYPOINT ["minecraft-skinsystem"] -CMD ["serve"] diff --git a/README.md b/README.md index c81d792..c7e2e85 100644 --- a/README.md +++ b/README.md @@ -1,61 +1,74 @@ -# Это заготовка для нормального файла +# Ely.by Minecraft Skinsystem -Для настройки Dev-окружения нужно склонировать проект в удобное место, -за тем сделать символьную ссылку в свой GOPATH: +Реализация API системы скинов для Minecraft v4. -```sh -# Выполнять, находясь внутри директории репозитория -mkdir -p $GOPATH/src/elyby -ln -s $PWD $GOPATH/src/elyby/minecraft-skinsystem -``` +## Config -Или можно склонировать репозиторий сразу в нужную локацию: +Конфигурация может задаваться посредством любого из перечисленных форматов файлов: JSON, TOML, YAML, HCL и +Java properties. Кроме того, параметры конфигурации могут перезаписываться доступными при запуске программы +ENV переменными. -```sh -git clone git@bitbucket.org:elyby/minecraft-skinsystem.git $GOPATH/src/elyby/minecraft-skinsystem -``` +> **Заметка**: ENV переменные именуются как KEY.SUBKEY.SUBSUBKEY, т.е. все символы должны быть заглавными, + а точки должны отделять уровень вложенности. -Нужно скопировать правильный docker-compose файл для желаемого окружения: +Пример файла конфигурации находится в [config.dist.yml](config.dist.yml). Внутри dist-файла есть комментарии, +поясняющие назначение тех или иных параметров. Для работы его следует скопировать в локальный `config.yml` +и отредактировать под свои нужды. -```sh -cp docker-compose.dev.yml docker-compose.yml # dev env -cp docker-compose.prod.yml docker-compose.yml # prod env -``` +## Развёртывание -И за тем всё это поднять: +Деплоить проект можно двумя способами: + +1. Скомпилировав и запустив бинарный файл, а также обеспечив ему доступ ко всем необходмым сервисам. + +2. Используя Docker и docker-compose. + +*Первый случай не буду описывать, т.к. долго, мучительно и никто так делать не будет, я гарантирую это*, +поэтому перейдём сразу ко второму. + +Прежде всего необходимо установить [Docker](https://docs.docker.com/engine/installation/) и +[docker-compose](https://docs.docker.com/compose/install/). + +Для запуска последней версии проекта достаточно скопировать содержимое файла +[docker-compose.prod.yml](docker-compose.prod.yml) в файл `docker-compose.yml` непосредственно на месте +установки, после чего ввести в консоль команду: ```sh docker-compose up -d ``` -Если нужно пересобрать весь контейнер, то выполняем следующее: +Web-приложение, amqp worker и все сопутствующие сервисы будут автоматически запущены. Данные из контейнеров +будут синхронизироваться в папку `data`. -``` -docker-compose stop app # Останавливаем конейтнер, если он ещё работает -docker-compose rm -f app # Удаляем конейтнер -docker-compose build app # Запускаем билд по новой -docker-compose up -d app # Поднимаем свежесобранный контейнер обратно -``` +## Разработка -### Шорткаты для разработки +Перво-наперво необходимо [установить последнюю версию Go](https://golang.org/doc/install) и сконфигурировать +переменную окружения GOPATH, а также установить инструмент контроля версий [dep](https://github.com/golang/dep). -Потом это надо преобразовать в нормальные доки. - -Run Redis: +Затем можно склонировать репозиторий хитрым способом, чтобы удовлетворить все прекрасные особенности Go: ```sh -docker run --rm \ --p 6379:6379 \ -redis:3.0-alpine +# Сперва создадим подпапку для приватных Go проектов Ely.by +mkdir -p $GOPATH/src/elyby +# Затем непосредственно клинируем репозиторий туда, где его ожидает увидеть Go +git clone git@gitlab.ely.by:elyby/minecraft-skinsystem.git $GOPATH/src/elyby/minecraft-skinsystem +# Переходим в папку проекта +cd $GOPATH/src/elyby/minecraft-skinsystem +# Устанавливаем зависимости +dep ensure ``` -Run RabbitMQ: +Чтобы запустить проект достаточно написать `go run main.go`, но без файла конфигурации и Redis +программа долго не проработает. Поэтому сперва копируем `config.dist.yml` в `config.yml` и, при необходимости, +затачиваем его под себя. + +Redis можно установить в систему самостоятельно, но гораздо удобнее воспользоваться готовыми сервисами, +описанными в [docker-compose.dev.yml](docker-compose.dev.yml). Для этого просто копируем `docker-compose.dev.yml` +и поднимаем сервисы: ```sh -docker run --rm \ --p 5672:5672 \ --e RABBITMQ_DEFAULT_USER=ely-skinsystem-app \ --e RABBITMQ_DEFAULT_PASS=ely-skinsystem-app-password \ --e RABBITMQ_DEFAULT_VHOST=/ely \ -rabbitmq:3.6 +cp docker-compose.dev.yml docker-compose.yml +docker-compose up -d ``` + +После этого `go run main.go serve` должен запустить web-сервер без дополнительной модификации файла конфигурации. diff --git a/cmd/root.go b/cmd/root.go index c13b8bf..0884715 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -32,6 +32,10 @@ func init() { func initConfig() { if cfgFile != "" { viper.SetConfigFile(cfgFile) + } else { + viper.SetConfigName("config") + viper.AddConfigPath("/data") + viper.AddConfigPath(".") } viper.AutomaticEnv() diff --git a/config.dist.yml b/config.dist.yml new file mode 100644 index 0000000..6270db8 --- /dev/null +++ b/config.dist.yml @@ -0,0 +1,51 @@ +# Main server configuration. Actually you don't want to change it, +# but you able to change host or port, that will be used by serve command +server: + host: localhost + port: 80 + +# Worker listen to AMQP events, so it should know how to connect to any +# AMQP provider (actually RabbitMQ). You should not escape any vhost +# characters, 'cause it will be done by application automatically +amqp: + host: localhost + port: 5672 + username: amqp-user + password: amqp-password + vhost: / + +# Both of web or worker depends on storage. +storage: + # For now app require Redis and don't support any other backends to store + # skins, but in the future we can have more backends. Poll size tune amount + # of connections to the redis. It's not recommended to set it less then 2 + # because it will lead to panic on high load. + redis: + host: localhost + port: 6379 + poolSize: 10 + + # Filesystem storage used to store capes. basePath specify absolute or relative + # path to storage and capesDirName specify which folder in this base path will + # be used to search capes. + filesystem: + basePath: data + capesDirName: capes + +# Accounts Ely.by internal API will be used in cases, when by some reasons +# information about user will be unavailable in the app storage. +api: + accounts: + host: https://account.ely.by + id: app-id + secret: secret + scopes: + - internal_account_info + +# StatsD can be used to collect metrics +# statsd: +# addr: localhost:3746 + +# Sentry can be used to collect app errors +# sentry: +# dsn: "https://public:private@your.sentry.io/1" diff --git a/data/statsd/.gitignore b/data/statsd/.gitignore deleted file mode 100644 index d6b7ef3..0000000 --- a/data/statsd/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore diff --git a/docker-compose.base.yml b/docker-compose.base.yml deleted file mode 100644 index acdfe60..0000000 --- a/docker-compose.base.yml +++ /dev/null @@ -1,20 +0,0 @@ -version: '2' -services: - redis: - image: redis:3.2-32bit - volumes: - - ./data/redis:/data - - rabbitmq: - image: rabbitmq:3.6 - environment: - RABBITMQ_DEFAULT_USER: "ely-skinsystem-app" - RABBITMQ_DEFAULT_PASS: "ely-skinsystem-app-password" - RABBITMQ_DEFAULT_VHOST: "/ely" - - statsd: - image: hopsoft/graphite-statsd - volumes: - - ./data/statsd:/opt/graphite/storage - - ./data/graphite-config:/opt/graphite/conf - - ./data/statsd-config/config.json:/opt/statsd/config.js diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index fd1f743..ba76495 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -1,35 +1,45 @@ +# This compose file contains necessary docker-compose config to quick start +# services required by app. Ports published to host. +# +# Usage: +# 1. Clone this file as docker-compose.yml: +# cp docker-compose.dev.yml docker-compose.yml +# +# 2. If necessary, then you can fix configuration to your environment. +# Then start all services: +# docker-compose up -d +# +# 3. Pass to the project configuration links to this services: +# amqp: +# host: localhost +# port: 5672 +# username: ely +# password: ely +# vhost: /ely +# +# storage: +# redis: +# host: localhost +# port: 6379 +# poolSize: 10 +# +# 4. After job is done all services can be stopped: +# docker-compose stop + version: '2' services: - app: - build: . - image: registry.ely.by/elyby/skinsystem:latest - ports: - - "80:80" - volumes: - - ./:/go/src/app - command: ["go", "run", "minecraft-skinsystem.go"] - links: - - redis - - rabbitmq - - statsd - environment: - ACCOUNTS_API_ID: "" - ACCOUNTS_API_SECRET: "" - STATSD_ADDR: "" + redis: + image: redis:3.2-32bit + ports: + - "6379:6379" + volumes: + - ./data/redis:/data - redis: - extends: - file: docker-compose.base.yml - service: redis - - rabbitmq: - extends: - file: docker-compose.base.yml - service: rabbitmq - - statsd: - extends: - file: docker-compose.base.yml - service: statsd - ports: - - "8123:80" + rabbitmq: + image: rabbitmq:3.6-manager + ports: + - "5672:5672" + environment: + RABBITMQ_DEFAULT_USER: "ely" + RABBITMQ_DEFAULT_PASS: "ely" + RABBITMQ_DEFAULT_VHOST: "/ely" diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 9d8bc79..d0fccc6 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -1,26 +1,33 @@ version: '2' services: - app: - image: registry.ely.by/elyby/skinsystem:latest - ports: - - "80:80" - links: - - redis - - rabbitmq - restart: always - environment: - ACCOUNTS_API_ID: "" - ACCOUNTS_API_SECRET: "" - STATSD_ADDR: "" + web: + image: registry.ely.by/elyby/skinsystem:latest + restart: always + ports: + - "80:80" + links: + - redis + volumes: + - ./data/capes:/data/capes - redis: - extends: - file: docker-compose.base.yml - service: redis - restart: always + worker: + image: registry.ely.by/elyby/skinsystem:latest + restart: always + links: + - redis + - rabbitmq + command: ["amqp-worker"] - rabbitmq: - extends: - file: docker-compose.base.yml - service: rabbitmq - restart: always + redis: + image: redis:3.2-32bit # 32-bit version used to decrease memory usage + restart: always + volumes: + - ./data/redis:/data + + rabbitmq: + image: rabbitmq:3.6 + restart: always + environment: + RABBITMQ_DEFAULT_USER: "ely-skinsystem-app" + RABBITMQ_DEFAULT_PASS: "ely-skinsystem-app-password" + RABBITMQ_DEFAULT_VHOST: "/ely"