diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..34869b80 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,21 @@ +/.git +/.github +/log/* +/tmp/* +/tmp/pids/* +!/log/.keep +!/tmp/.keep +!/tmp/pids/ +!/tmp/pids/.keep +/config/master.key +/.env +/.DS_STORE +/public/packs +/public/packs-test +/node_modules +/yarn-error.log +/yarn-debug.log* +/.yarn-integrity +/app/assets/builds/* +!/app/assets/builds/.keep +/docker-compose* diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..6313b56c --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3cab4970..60392e12 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,16 +1,15 @@ -# This workflow uses actions that are not certified by GitHub. They are -# provided by a third-party and are governed by separate terms of service, -# privacy policy, and support documentation. -# -# This workflow will install a prebuilt Ruby version, install dependencies, and -# run tests and linters. name: "CI" + on: push: branches: [main] pull_request: branches: [main] workflow_dispatch: + +env: + IMAGENAME: registry.digitalocean.com/nsgcr/nrdb-api-server + jobs: test: name: Test @@ -83,3 +82,37 @@ jobs: run: bundle exec brakeman -q -w2 # - name: Lint Ruby files # run: bin/rubocop --parallel + + + build_and_push: + name: Build docker image + needs: [test, lint] + runs-on: ubuntu-latest + steps: + + - name: Checkout the repo + uses: actions/checkout@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build image + run: docker build -t $IMAGENAME:latest . + + - name: Install doctl + if: github.ref == 'refs/heads/main' + uses: digitalocean/action-doctl@v2 + with: + token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} + + - name: Log in to DO Container Registry + if: github.ref == 'refs/heads/main' + run: doctl registry login --expiry-seconds 600 + + - name: Tag image with run id + if: github.ref == 'refs/heads/main' + run: docker tag $IMAGENAME:latest $IMAGENAME:${{ github.run_id }} + + - name: Push image to DO Container Registry + if: github.ref == 'refs/heads/main' + run: docker push $IMAGENAME:${{ github.run_id }} && docker push $IMAGENAME:latest diff --git a/Dockerfile b/Dockerfile index 2bd3a64c..8d36d528 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,10 @@ -FROM ruby:3.1 +# Inspired by https://dennmart.com/articles/building-lean-docker-images-for-rails-apps/ -RUN apt-get update -qq && apt-get install -y postgresql-client +##################################################################### +FROM ruby:3.2.3-alpine3.19 AS build + +RUN apk -U upgrade && apk add --no-cache gcompat postgresql-client build-base libpq-dev tzdata \ + && rm -rf /var/cache/apk/* RUN gem install rails @@ -13,17 +17,33 @@ RUN mkdir -p $RAILS_ROOT/tmp/pids # Set our working directory inside the image WORKDIR $RAILS_ROOT -# throw errors if Gemfile has been modified since Gemfile.lock +# Throw errors if Gemfile has been modified since Gemfile.lock RUN bundle config --global frozen 1 -RUN pwd +COPY Gemfile Gemfile.lock $RAILS_ROOT/ -COPY Gemfile Gemfile.lock ./ +# Install gems into the vendor/bundle directory in the workspace. +RUN bundle config set --local path "vendor/bundle" && \ + bundle config set force_ruby_platform true && \ + bundle install --jobs 4 --retry 3 -RUN bundle install +COPY . $RAILS_ROOT/ + + +##################################################################### +FROM ruby:3.2.3-alpine3.19 AS final + +RUN apk -U upgrade && apk add --no-cache gcompat postgresql-client tzdata \ + && rm -rf /var/cache/apk/* + +ENV RAILS_ROOT /var/www/nrdb-api +WORKDIR $RAILS_ROOT +RUN bundle config set --local path "vendor/bundle" +COPY --from=build $RAILS_ROOT $RAILS_ROOT/ -ENTRYPOINT ["./entrypoint.sh"] EXPOSE 3000 +RUN chmod +x ./entrypoint.sh +ENTRYPOINT ["./entrypoint.sh"] # Start the main process. -CMD ["rails", "server", "-b", "0.0.0.0"] +CMD ["/bin/sh", "-c", "bundle exec rails server -b 0.0.0.0"] diff --git a/Gemfile b/Gemfile index 7a02b1b7..0cbc5bfb 100644 --- a/Gemfile +++ b/Gemfile @@ -3,6 +3,10 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby "~> 3.1" +# Gems that have trouble with native packages on alpine. +gem 'google-protobuf', force_ruby_platform: true +gem 'nokogiri', force_ruby_platform: true + # Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main" gem "rails", ">= 7.0.7.1" diff --git a/Gemfile.lock b/Gemfile.lock index 30dffade..e4ccddd4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -96,10 +96,7 @@ GEM i18n (>= 1.8.11, < 2) globalid (1.1.0) activesupport (>= 5.0) - google-protobuf (3.24.2-aarch64-linux) - google-protobuf (3.24.2-arm64-darwin) - google-protobuf (3.24.2-x86_64-darwin) - google-protobuf (3.24.2-x86_64-linux) + google-protobuf (3.25.2) googleapis-common-protos-types (1.8.0) google-protobuf (~> 3.18) i18n (1.14.1) @@ -125,6 +122,7 @@ GEM marcel (1.0.2) method_source (1.0.0) mini_mime (1.1.5) + mini_portile2 (2.8.5) minitest (5.19.0) msgpack (1.7.2) mustache (1.1.1) @@ -138,13 +136,8 @@ GEM net-smtp (0.3.3) net-protocol nio4r (2.7.0) - nokogiri (1.15.4-aarch64-linux) - racc (~> 1.4) - nokogiri (1.15.4-arm64-darwin) - racc (~> 1.4) - nokogiri (1.15.4-x86_64-darwin) - racc (~> 1.4) - nokogiri (1.15.4-x86_64-linux) + nokogiri (1.16.1) + mini_portile2 (~> 2.8.2) racc (~> 1.4) opentelemetry-api (1.2.2) opentelemetry-common (0.20.0) @@ -344,7 +337,7 @@ GEM pg (1.5.3) puma (5.6.8) nio4r (~> 2.0) - racc (1.7.1) + racc (1.7.3) rack (2.2.8) rack-cors (2.0.1) rack (>= 2.0.0) @@ -438,6 +431,7 @@ GEM PLATFORMS aarch64-linux + ruby universal-darwin-20 x86_64-linux @@ -450,8 +444,10 @@ DEPENDENCIES debug factory_bot_rails faker + google-protobuf jsonapi-resources jwt + nokogiri opentelemetry-exporter-otlp opentelemetry-instrumentation-all opentelemetry-sdk diff --git a/README.md b/README.md index b6dc8351..e927cbd8 100644 --- a/README.md +++ b/README.md @@ -16,17 +16,17 @@ This depends on the data from https://github.com/NetrunnerDB/netrunner-cards-jso ``` echo "RAILS_ENV=development" > .env -# This will not be needed if you have already created this network. -docker network create null_signal -docker compose build cp config/database.example.yml config/database.yml -docker compose up -d db -# Wait until docker compose logs db | tail shows 'database system is ready to accept connections' -docker compose run nrdb_api_server rake db:reset +docker compose -f docker-compose.yml -f docker-compose.override.init.yml up -d +``` +Wait until `docker compose logs nrdb_api_server | tail` shows `Listening on http://0.0.0.0:3000`. + +Test that `http://localhost:3000/api/docs/` loads in your browser. Afterwords, + +``` docker compose up -d -# Import the card data from the netrunner-cards-json repo -docker compose exec nrdb_api_server rails cards:import ``` +Is enough to spin up the containers, unless you want to restart the db from scratch (use the above example with init.yml) To run tests in your docker container, you will need to override the environment, like so: ``` diff --git a/docker-compose.override.init.yml b/docker-compose.override.init.yml new file mode 100644 index 00000000..3ba6d798 --- /dev/null +++ b/docker-compose.override.init.yml @@ -0,0 +1,12 @@ +version: "3.2" + +services: + + nrdb_api_server: + command: + - /bin/sh + - -c + - | + rake db:reset + bundle exec rails cards:import + bundle exec rails server -b 0.0.0.0 diff --git a/docker-compose.yml b/docker-compose.yml index 99193b1e..d7920288 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,16 +2,26 @@ version: "3.2" services: # service configuration for our dockerized Rails app + + netrunner_cards_json: + restart: none + image: registry.digitalocean.com/nsgcr/netrunner-cards-json:latest + build: https://github.com/NetrunnerDB/netrunner-cards-json.git#main + volumes: + - netrunner-cards-json:/mnt/netrunner-cards-json + nrdb_api_server: restart: unless-stopped + image: registry.digitalocean.com/nsgcr/nrdb-api-server:latest + # build the Dockerfile next to this file, tag the built image with above image name + build: . + + ports: + - "3000:3000" networks: - - null_signal - backend - # use the Dockerfile next to this file - build: . - # sources environment variable configuration for our app env_file: .env @@ -20,19 +30,20 @@ services: POSTGRES_PASSWORD: netrunnerdb RAILS_ENV: $RAILS_ENV - # makes the app container aware of the DB container - links: + # starts the app container after the DB and netrunner_cards_json containers + depends_on: - db + - netrunner_cards_json volumes: - - .:/var/www/nrdb-api/ - - ../netrunner-cards-json/:/netrunner-cards-json + - ./config/database.yml:/var/www/nrdb-api/config/database.yml + - netrunner-cards-json:/netrunner-cards-json - nrdb-api-logs:/var/www/nrdb-api/log # service configuration for our database db: restart: unless-stopped - image: postgres:14.5 + image: postgres:14.5-alpine networks: - backend @@ -46,9 +57,8 @@ services: networks: backend: - null_signal: - external: true volumes: nrdb-api-logs: nrdb-api-postgres: + netrunner-cards-json: diff --git a/entrypoint.sh b/entrypoint.sh index 1701c1e3..f5fe4893 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh set -e