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