From cdfd569be1a88b5658506ecd9fb3b559a016c04f Mon Sep 17 00:00:00 2001 From: Alexander Olofsson <alexander.olofsson@liu.se> Date: Mon, 8 Oct 2018 16:31:23 +0200 Subject: [PATCH] Adding modern CI --- .dockerignore | 27 ++++++ .gitignore | 7 ++ .gitlab-ci.yml | 85 +++++++++++++++++ .k8s/deployment.yaml | 48 ++++++++++ .k8s/ingress.yaml | 17 ++++ .k8s/secret.yaml | 8 ++ .k8s/service.yaml | 17 ++++ Dockerfile | 15 +++ Gemfile | 3 +- Gemfile.lock | 222 ------------------------------------------- config/database.yml | 7 +- docker/entrypoint.sh | 14 +++ 12 files changed, 244 insertions(+), 226 deletions(-) create mode 100644 .dockerignore create mode 100644 .gitlab-ci.yml create mode 100644 .k8s/deployment.yaml create mode 100644 .k8s/ingress.yaml create mode 100644 .k8s/secret.yaml create mode 100644 .k8s/service.yaml create mode 100644 Dockerfile delete mode 100644 Gemfile.lock create mode 100755 docker/entrypoint.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..a2ba33e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,27 @@ +# +.git + +# Ignore bundler files +/.bundle +/vendor/ruby + +# Ignore temporary files +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore uploaded files in development +/storage/* + +/node_modules +/yarn-error.log + +/public/assets +.byebug_history + +# Ignore master key for decrypting credentials and more. +/config/master.key + +# Ignore databases +/db diff --git a/.gitignore b/.gitignore index 211a27a..3e017d7 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,10 @@ # Ignore bundler config. /.bundle +/vendor/ruby + +# Ignore gemfile lock +/Gemfile.lock # Ignore all logfiles and tempfiles. /log/* @@ -24,3 +28,6 @@ # Ignore master key for decrypting credentials and more. /config/master.key + +# Ignore databases +/db diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..72554b4 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,85 @@ +--- +stages: + - test + - build + - deploy + +# test: +# stage: test +# image: ruby:2.5 +# script: +# - bundle install --path=vendor +# - bundle exec rake test +# cache: +# paths: +# - vendor/ruby + +build:image: + stage: build + image: + name: gcr.io/kaniko-project/executor:debug + entrypoint: ["busybox/sh", "-c"] # Fix for Docker <= 17.03 + script: + - mkdir -p /root/.docker + - echo "{\"auths\":{\"${CI_REGISTRY}\":{\"username\":\"${CI_REGISTRY_USER}\",\"password\":\"${CI_JOB_TOKEN}\"}}}" > /root/.docker/config.json + - /kaniko/executor --context ${CI_PROJECT_DIR} --dockerfile Dockerfile $DOCKER_PROXY --destination "${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA}" + +.deploy: + stage: deploy + image: lachlanevenson/k8s-kubectl + script: + # Create an environment-specific deployment + - 'sed -e "s/^ name: \(.*\)/ name: ${CI_ENVIRONMENT_SLUG}-\1/" + -e "s/environment: .*/environment: ${CI_ENVIRONMENT_SLUG}/g" + -e "s/app: \(.*\)/app: ${CI_ENVIRONMENT_SLUG}-\1/g" -i .k8s/*.yaml' + # Set up the ingress to route to the environment-specific service + - 'sed -e "s/serviceName: \(.*\)/serviceName: ${CI_ENVIRONMENT_SLUG}-\1/" + .e "s/host: .*/host: $(echo ${CI_ENVIRONMENT_URL} | sed -e "s|https\?://||")/" -i .k8s/ingress.yaml' + # Configure the deployment to use this commit, and fix secret ref to use production secret + - 'sed -e "s!image: .*!image: ${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA}!" + -e "s/^\( \{18\}\)name: \(.*\)/\1name: ${CI_ENVIRONMENT_SLUG}-\2/" -i .k8s/deployment.yaml' + # Configure the database URL for production + - 'sed -e "s/database-url: .*/database-url: $(echo $DATABASE_URL | base64 | tr -d "\n")/" -i .k8s/secret.yaml' + + - kubectl apply -f .k8s/secret.yaml + - kubectl apply -f .k8s/deployment.yaml + - kubectl apply -f .k8s/service.yaml + - kubectl apply -f .k8s/ingress.yaml + only: + - master + +deploy:development: + extends: .deploy + environment: + name: development + url: http://k8s-example-dev.kubernetes.it.liu.se + on_stop: deploy:development:stop + +deploy:development:stop: + extends: .deploy + script: kubectl scale deploy/${CI_ENVIRONMENT_SLUG}-k8s-example --replicas=0 + environment: + name: development + action: stop + +deploy:test: + extends: .deploy + environment: + name: test + url: http://k8s-example-test.kubernetes.it.liu.se + on_stop: deploy:test:stop + when: manual + +deploy:test:stop: + extends: .deploy + script: kubectl scale deploy/${CI_ENVIRONMENT_SLUG}-k8s-example --replicas=0 + environment: + name: test + action: stop + +deploy:production: + extends: .deploy + environment: + name: production + url: http://k8s-example.kubernetes.it.liu.se + when: manual diff --git a/.k8s/deployment.yaml b/.k8s/deployment.yaml new file mode 100644 index 0000000..62e3af3 --- /dev/null +++ b/.k8s/deployment.yaml @@ -0,0 +1,48 @@ +--- +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + labels: + app: k8s-example + environment: development + name: k8s-example +spec: + replicas: 1 + selector: + matchLabels: + app: k8s-example + environment: development + template: + metadata: + labels: + app: k8s-example + environment: development + spec: + containers: + - env: + - name: RAILS_ENV + valueFrom: + fieldRef: + fieldPath: metadata.labels['environment'] + - name: DATABASE_URL # Only used in production + valueFrom: + secretKeyRef: + name: k8s-example + key: database-url + image: gitlab.liu.se:5000/aleol57/kubernetes-example:latest + imagePullPolicy: Always + name: application + ports: + - containerPort: 3000 + protocol: TCP + readinessProbe: + tcpSocket: + port: 3000 + resources: + limits: + cpu: 250m + memory: 256Mi + requests: + cpu: 15m + memory: 42Mi + restartPolicy: Always diff --git a/.k8s/ingress.yaml b/.k8s/ingress.yaml new file mode 100644 index 0000000..1d3718c --- /dev/null +++ b/.k8s/ingress.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: k8s-example + labels: + app: k8s-example + environment: development +spec: + rules: + - host: example.com + http: + paths: + - backend: + serviceName: k8s-example + servicePort: 3000 + path: / diff --git a/.k8s/secret.yaml b/.k8s/secret.yaml new file mode 100644 index 0000000..e1e9c73 --- /dev/null +++ b/.k8s/secret.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: v1 +data: + database-url: cG9zdGdyZXM6Ly91c2VyOnBhc3NAc2VydmVyL2RhdGFiYXNlCg== +kind: Secret +metadata: + name: k8s-example +type: Opaque diff --git a/.k8s/service.yaml b/.k8s/service.yaml new file mode 100644 index 0000000..9198217 --- /dev/null +++ b/.k8s/service.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: k8s-example + environment: development + name: k8s-example +spec: + ports: + - port: 3000 + protocol: TCP + targetPort: 3000 + selector: + app: k8s-example + environment: development + type: ClusterIP diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..1eee5d8 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +FROM ruby:2.5 + +RUN apt-get update -qq \ + && apt-get install -y build-essential libpq-dev nodejs \ + && apt-get autoremove -yqq + +WORKDIR /app + +COPY Gemfile Gemfile.loc[k] /app/ + +RUN bundle install --path=vendor + +COPY docker/entrypoint.sh /entrypoint + +CMD ["/entrypoint"] diff --git a/Gemfile b/Gemfile index 79998b9..6c458bf 100644 --- a/Gemfile +++ b/Gemfile @@ -1,7 +1,7 @@ source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } -ruby '2.5.1' +#ruby '2.5.1' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' gem 'rails', '~> 5.2.0' @@ -39,6 +39,7 @@ gem 'bootsnap', '>= 1.1.0', require: false group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] + gem 'sqlite3', '~> 1.3.6' end group :development do diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index 96bcf9c..0000000 --- a/Gemfile.lock +++ /dev/null @@ -1,222 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - actioncable (5.2.0) - actionpack (= 5.2.0) - nio4r (~> 2.0) - websocket-driver (>= 0.6.1) - actionmailer (5.2.0) - actionpack (= 5.2.0) - actionview (= 5.2.0) - activejob (= 5.2.0) - mail (~> 2.5, >= 2.5.4) - rails-dom-testing (~> 2.0) - actionpack (5.2.0) - actionview (= 5.2.0) - activesupport (= 5.2.0) - rack (~> 2.0) - rack-test (>= 0.6.3) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.2.0) - activesupport (= 5.2.0) - builder (~> 3.1) - erubi (~> 1.4) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.0.3) - activejob (5.2.0) - activesupport (= 5.2.0) - globalid (>= 0.3.6) - activemodel (5.2.0) - activesupport (= 5.2.0) - activerecord (5.2.0) - activemodel (= 5.2.0) - activesupport (= 5.2.0) - arel (>= 9.0) - activestorage (5.2.0) - actionpack (= 5.2.0) - activerecord (= 5.2.0) - marcel (~> 0.3.1) - activesupport (5.2.0) - concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) - addressable (2.5.2) - public_suffix (>= 2.0.2, < 4.0) - archive-zip (0.11.0) - io-like (~> 0.3.0) - arel (9.0.0) - bindex (0.5.0) - bootsnap (1.3.0) - msgpack (~> 1.0) - builder (3.2.3) - byebug (10.0.2) - capybara (3.0.3) - addressable - mini_mime (>= 0.1.3) - nokogiri (~> 1.8) - rack (>= 1.6.0) - rack-test (>= 0.6.3) - xpath (~> 3.0) - childprocess (0.9.0) - ffi (~> 1.0, >= 1.0.11) - chromedriver-helper (1.2.0) - archive-zip (~> 0.10) - nokogiri (~> 1.8) - coffee-rails (4.2.2) - coffee-script (>= 2.2.0) - railties (>= 4.0.0) - coffee-script (2.4.1) - coffee-script-source - execjs - coffee-script-source (1.12.2) - concurrent-ruby (1.0.5) - crass (1.0.4) - erubi (1.7.1) - execjs (2.7.0) - ffi (1.9.23) - globalid (0.4.1) - activesupport (>= 4.2.0) - i18n (1.0.1) - concurrent-ruby (~> 1.0) - io-like (0.3.0) - jbuilder (2.7.0) - activesupport (>= 4.2.0) - multi_json (>= 1.2) - libv8 (6.3.292.48.1) - listen (3.1.5) - rb-fsevent (~> 0.9, >= 0.9.4) - rb-inotify (~> 0.9, >= 0.9.7) - ruby_dep (~> 1.2) - loofah (2.2.2) - crass (~> 1.0.2) - nokogiri (>= 1.5.9) - mail (2.7.0) - mini_mime (>= 0.1.1) - marcel (0.3.2) - mimemagic (~> 0.3.2) - method_source (0.9.0) - mimemagic (0.3.2) - mini_mime (1.0.0) - mini_portile2 (2.3.0) - mini_racer (0.1.15) - libv8 (~> 6.3) - minitest (5.11.3) - msgpack (1.2.4) - multi_json (1.13.1) - nio4r (2.3.1) - nokogiri (1.8.2) - mini_portile2 (~> 2.3.0) - pg (1.0.0) - public_suffix (3.0.2) - puma (3.11.4) - rack (2.0.5) - rack-test (1.0.0) - rack (>= 1.0, < 3) - rails (5.2.0) - actioncable (= 5.2.0) - actionmailer (= 5.2.0) - actionpack (= 5.2.0) - actionview (= 5.2.0) - activejob (= 5.2.0) - activemodel (= 5.2.0) - activerecord (= 5.2.0) - activestorage (= 5.2.0) - activesupport (= 5.2.0) - bundler (>= 1.3.0) - railties (= 5.2.0) - sprockets-rails (>= 2.0.0) - rails-dom-testing (2.0.3) - activesupport (>= 4.2.0) - nokogiri (>= 1.6) - rails-html-sanitizer (1.0.4) - loofah (~> 2.2, >= 2.2.2) - railties (5.2.0) - actionpack (= 5.2.0) - activesupport (= 5.2.0) - method_source - rake (>= 0.8.7) - thor (>= 0.18.1, < 2.0) - rake (12.3.1) - rb-fsevent (0.10.3) - rb-inotify (0.9.10) - ffi (>= 0.5.0, < 2) - ruby_dep (1.5.0) - rubyzip (1.2.1) - sass (3.5.6) - sass-listen (~> 4.0.0) - sass-listen (4.0.0) - rb-fsevent (~> 0.9, >= 0.9.4) - rb-inotify (~> 0.9, >= 0.9.7) - sass-rails (5.0.7) - railties (>= 4.0.0, < 6) - sass (~> 3.1) - sprockets (>= 2.8, < 4.0) - sprockets-rails (>= 2.0, < 4.0) - tilt (>= 1.1, < 3) - selenium-webdriver (3.11.0) - childprocess (~> 0.5) - rubyzip (~> 1.2) - spring (2.0.2) - activesupport (>= 4.2) - spring-watcher-listen (2.0.1) - listen (>= 2.7, < 4.0) - spring (>= 1.2, < 3.0) - sprockets (3.7.1) - concurrent-ruby (~> 1.0) - rack (> 1, < 3) - sprockets-rails (3.2.1) - actionpack (>= 4.0) - activesupport (>= 4.0) - sprockets (>= 3.0.0) - thor (0.20.0) - thread_safe (0.3.6) - tilt (2.0.8) - turbolinks (5.1.1) - turbolinks-source (~> 5.1) - turbolinks-source (5.1.0) - tzinfo (1.2.5) - thread_safe (~> 0.1) - uglifier (4.1.10) - execjs (>= 0.3.0, < 3) - web-console (3.6.2) - actionview (>= 5.0) - activemodel (>= 5.0) - bindex (>= 0.4.0) - railties (>= 5.0) - websocket-driver (0.7.0) - websocket-extensions (>= 0.1.0) - websocket-extensions (0.1.3) - xpath (3.0.0) - nokogiri (~> 1.8) - -PLATFORMS - ruby - -DEPENDENCIES - bootsnap (>= 1.1.0) - byebug - capybara (>= 2.15, < 4.0) - chromedriver-helper - coffee-rails (~> 4.2) - jbuilder (~> 2.5) - listen (>= 3.0.5, < 3.2) - mini_racer - pg (>= 0.18, < 2.0) - puma (~> 3.11) - rails (~> 5.2.0) - sass-rails (~> 5.0) - selenium-webdriver - spring - spring-watcher-listen (~> 2.0.0) - turbolinks (~> 5) - tzinfo-data - uglifier (>= 1.3.0) - web-console (>= 3.3.0) - -RUBY VERSION - ruby 2.5.1p57 - -BUNDLED WITH - 1.16.1 diff --git a/config/database.yml b/config/database.yml index 986378c..d0ab409 100644 --- a/config/database.yml +++ b/config/database.yml @@ -15,7 +15,7 @@ # gem 'pg' # default: &default - adapter: postgresql + adapter: sqlite3 encoding: unicode # For details on connection pooling, see Rails configuration guide # http://guides.rubyonrails.org/configuring.html#database-pooling @@ -23,7 +23,7 @@ default: &default development: <<: *default - database: demo_development + database: db/development.db # The specified database role being used to connect to postgres. # To create additional roles in postgres see `$ createuser --help`. @@ -57,7 +57,7 @@ development: # Do not set this db to the same as development or production. test: <<: *default - database: demo_test + database: db/test.db # As with config/secrets.yml, you never want to store sensitive information, # like your database password, in your source code. If your source code is @@ -80,4 +80,5 @@ test: # production: <<: *default + adapter: postgres url: <%= ENV['DATABASE_URL'] %> diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100755 index 0000000..eff71a8 --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +cd /app || exit 1 + +if ! bundle exec rake db:migrate; then + echo + echo "== Failed to migrate. Running setup first." + echo + bundle exec rake db:setup && \ + bundle exec rake db:migrate +fi + +bundle exec rake assets:precompile +bundle exec puma -- GitLab