add example app code
parent
b8173f110b
commit
3bdb4657ff
@ -0,0 +1,3 @@
|
||||
infra/.terraform*
|
||||
infra/terraform-gcp-service-account.json
|
||||
infra/terraform.tfstate*
|
@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
|
||||
KUBE_FEATURE_BRANCHES=`kubectl get po -n ${APP_NAME} -l "app.kubernetes.io/name=${APP_NAME}" -o jsonpath="{.items[*].metadata.labels['app\.kubernetes\.io/instance']}"`
|
||||
|
||||
GIT_BRANCHES=`git fetch origin && git branch --list --remote | sed 's/ origin\///g'`
|
||||
|
||||
for kube_branch in $KUBE_FEATURE_BRANCHES; do
|
||||
echo "Checking branch ${kube_branch}"
|
||||
git_branch_still_exists=false
|
||||
for git_branch in $GIT_BRANCHES; do
|
||||
if [ "${git_branch}" == "feature/${kube_branch}" ]; then
|
||||
git_branch_still_exists=true
|
||||
echo "Git branch ${git_branch} still exists, instance ${kube_branch} will not be deleted."
|
||||
fi
|
||||
done
|
||||
if [ "${git_branch_still_exists}" = false ]; then
|
||||
echo "Git branch corresponding to instance ${kube_branch} has been deleted, deleting instance..."
|
||||
kubectl delete all,ingressroute,pvc,pv -n ${APP_NAME} -l app.kubernetes.io/instance=${kube_branch}
|
||||
fi
|
||||
done
|
@ -0,0 +1,72 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
namespace: ${APP_NAME}
|
||||
name: ${APP_NAME}-${INSTANCE_NAME}
|
||||
labels:
|
||||
app.kubernetes.io/name: ${APP_NAME}
|
||||
app.kubernetes.io/instance: ${INSTANCE_NAME}
|
||||
spec:
|
||||
selector:
|
||||
app.kubernetes.io/name: ${APP_NAME}
|
||||
app.kubernetes.io/instance: ${INSTANCE_NAME}
|
||||
ports:
|
||||
- protocol: TCP
|
||||
name: http
|
||||
port: 8080
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
namespace: ${APP_NAME}
|
||||
name: ${APP_NAME}-${INSTANCE_NAME}
|
||||
labels:
|
||||
app.kubernetes.io/name: ${APP_NAME}
|
||||
app.kubernetes.io/instance: ${INSTANCE_NAME}
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: ${APP_NAME}
|
||||
app.kubernetes.io/instance: ${INSTANCE_NAME}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: ${APP_NAME}
|
||||
app.kubernetes.io/instance: ${INSTANCE_NAME}
|
||||
spec:
|
||||
terminationGracePeriodSeconds: 20
|
||||
containers:
|
||||
- name: ${APP_NAME}
|
||||
image: ${IMAGE}
|
||||
imagePullPolicy: "Always"
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 8080
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
namespace: ${APP_NAME}
|
||||
name: ${APP_NAME}-${INSTANCE_NAME}
|
||||
labels:
|
||||
app.kubernetes.io/name: ${APP_NAME}
|
||||
app.kubernetes.io/instance: ${INSTANCE_NAME}
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
traefik.ingress.kubernetes.io/router.tls: "true"
|
||||
spec:
|
||||
entryPoints:
|
||||
- https
|
||||
routes:
|
||||
- match: Host(`${INSTANCE_NAME}-${APP_NAME}.${APP_DOMAIN}`)
|
||||
kind: Rule
|
||||
services:
|
||||
- namespace: ${APP_NAME}
|
||||
name: ${APP_NAME}-${INSTANCE_NAME}
|
||||
port: 8080
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
domains:
|
||||
- main: "*.${APP_DOMAIN}"
|
@ -0,0 +1,12 @@
|
||||
#!/bin/bash +x
|
||||
|
||||
BASTION_STATE=`gcloud compute instances describe $GCP_KUBE_CLUSTER-bastion --zone $GCP_REGION-a --format=json | jq ".status"`
|
||||
TERMINATED_STATE="\"TERMINATED\""
|
||||
|
||||
if [[ $BASTION_STATE == $TERMINATED_STATE ]]; then
|
||||
echo "Start bastion"
|
||||
gcloud compute instances start $GCP_KUBE_CLUSTER-bastion --zone $GCP_REGION-a
|
||||
sleep 10
|
||||
else
|
||||
echo "Bastion started already"
|
||||
fi
|
@ -0,0 +1,142 @@
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: default
|
||||
|
||||
environment:
|
||||
APP_NAME: example-app
|
||||
GCP_PROJECT: <GCP_PROJECT_ID>
|
||||
GCP_REGISTRY: <GCP_REGISTRY_URL>
|
||||
GCP_REGION: <GCP_REGION>
|
||||
GCP_KUBE_CLUSTER: <GCP_GKE_CLUSTER_NAME>
|
||||
GCP_DOMAIN: <GCP_DOMAIN_NAME>
|
||||
|
||||
steps:
|
||||
- name: google authentication & bastion
|
||||
image: google/cloud-sdk
|
||||
environment:
|
||||
GCP_CREDENTIALS:
|
||||
from_secret: gcp-credentials
|
||||
commands:
|
||||
- mkdir .credentials
|
||||
- echo -n "$GCP_CREDENTIALS" > .credentials/gcp-key.json
|
||||
- gcloud auth activate-service-account --key-file .credentials/gcp-key.json
|
||||
- gcloud --quiet config set project $GCP_PROJECT
|
||||
- gcloud config set compute/region $GCP_REGION
|
||||
- gcloud --quiet container clusters get-credentials $GCP_KUBE_CLUSTER
|
||||
- apt-get install -y jq
|
||||
- bash .drone-kube/start_bastion.sh
|
||||
when:
|
||||
branch:
|
||||
- feature/*
|
||||
- fix/*
|
||||
- refactor/*
|
||||
- intg/*
|
||||
- trunk
|
||||
event:
|
||||
- push
|
||||
|
||||
- name: build image
|
||||
image: docker:dind
|
||||
volumes:
|
||||
- name: dockersock
|
||||
path: /var/run/docker.sock
|
||||
environment:
|
||||
DOCKER_HOST: unix:///var/run/docker.sock
|
||||
commands:
|
||||
- export VERSION=$(echo $DRONE_BRANCH | sed "s/\\//-/g"):latest
|
||||
- export VERSION_SHA=$(echo $DRONE_BRANCH | sed "s/\\//-/g"):$DRONE_COMMIT_SHA
|
||||
- docker build . -t $GCP_REGISTRY/$APP_NAME/$VERSION
|
||||
- docker tag $GCP_REGISTRY/$APP_NAME/$VERSION $GCP_REGISTRY/$APP_NAME/$VERSION_SHA
|
||||
when:
|
||||
branch:
|
||||
- feature/*
|
||||
- fix/*
|
||||
- refactor/*
|
||||
- intg/*
|
||||
- trunk
|
||||
event:
|
||||
- push
|
||||
|
||||
- name: push to GCP Artifact registry
|
||||
image: google/cloud-sdk
|
||||
volumes:
|
||||
- name: dockersock
|
||||
path: /var/run/docker.sock
|
||||
environment:
|
||||
DOCKER_HOST: unix:///var/run/docker.sock
|
||||
commands:
|
||||
- gcloud auth activate-service-account --key-file .credentials/gcp-key.json
|
||||
- gcloud auth print-access-token | docker login -u oauth2accesstoken --password-stdin https://$GCP_REGION-docker.pkg.dev
|
||||
- export VERSION=$(echo $DRONE_BRANCH | sed "s/\\//-/g"):latest
|
||||
- export VERSION_SHA=$(echo $DRONE_BRANCH | sed "s/\\//-/g"):$DRONE_COMMIT_SHA
|
||||
- docker push $GCP_REGISTRY/$APP_NAME/$VERSION
|
||||
- docker push $GCP_REGISTRY/$APP_NAME/$VERSION_SHA
|
||||
when:
|
||||
branch:
|
||||
- feature/*
|
||||
- fix/*
|
||||
- refactor/*
|
||||
- intg/*
|
||||
- trunk
|
||||
event:
|
||||
- push
|
||||
|
||||
- name: deploy review to gke cluster
|
||||
image: google/cloud-sdk
|
||||
commands:
|
||||
- mkdir -p ~/.ssh
|
||||
- chmod 700 ~/.ssh
|
||||
- apt-get update && apt-get install gettext-base -y
|
||||
- gcloud auth activate-service-account --key-file .credentials/gcp-key.json
|
||||
- gcloud config set project $GCP_PROJECT
|
||||
- gcloud container clusters get-credentials $GCP_KUBE_CLUSTER --region=$GCP_REGION
|
||||
- gcloud compute ssh bob@$GCP_KUBE_CLUSTER-bastion --zone $GCP_REGION-a -- -4 -L8888:127.0.0.1:8888 -fN -f /dev/null
|
||||
- export INSTANCE_NAME=$(echo $DRONE_BRANCH | sed "s/\\//-/g" | sed "s/feature-//g" | sed "s/^fix-//g" | sed "s/^refactor-//g" | sed "s/^intg-//g")
|
||||
- export IMAGE=$GCP_REGISTRY/$APP_NAME/feature-$INSTANCE_NAME:$DRONE_COMMIT_SHA
|
||||
- export HTTPS_PROXY=127.0.0.1:8888
|
||||
- echo $IMAGE
|
||||
- kubectl create namespace $APP_NAME || echo "Namespace $APP_NAME exists"
|
||||
- envsubst < .drone-kube/deployment.yml > deployment.yml
|
||||
- kubectl apply -f deployment.yml
|
||||
- echo "The application is available at https://$INSTANCE_NAME-$APP_NAME.$GCP_DOMAIN"
|
||||
when:
|
||||
branch:
|
||||
- feature/*
|
||||
- fix/*
|
||||
- refactor/*
|
||||
- intg/*
|
||||
event: push
|
||||
|
||||
- name: destroy review app in gke cluster
|
||||
image: google/cloud-sdk
|
||||
commands:
|
||||
- mkdir -p ~/.ssh
|
||||
- chmod 700 ~/.ssh
|
||||
- apt-get update && apt-get install gettext-base -y
|
||||
- gcloud config set project $GCP_PROJECT
|
||||
- gcloud auth activate-service-account --key-file .credentials/gcp-key.json
|
||||
- gcloud container clusters get-credentials $GCP_KUBE_CLUSTER --region=$GCP_REGION
|
||||
- gcloud compute ssh bob@$GCP_KUBE_CLUSTER-bastion --zone $GCP_REGION-a -- -4 -L8888:127.0.0.1:8888 -fN -f /dev/null
|
||||
- export HTTPS_PROXY=127.0.0.1:8888
|
||||
- bash .drone-kube/cleanup.sh
|
||||
when:
|
||||
branch:
|
||||
- trunk
|
||||
event:
|
||||
- push
|
||||
|
||||
volumes:
|
||||
- name: cache
|
||||
host:
|
||||
path: /tmp/drone/cache/bundle
|
||||
- name: cache-deploy
|
||||
host:
|
||||
path: /tmp/drone/cache-deploy/bundle
|
||||
- name: dockersock
|
||||
host:
|
||||
path: /var/run/docker.sock
|
||||
|
||||
---
|
||||
kind: secret
|
||||
name: gcp-credentials
|
||||
data: <GCP_ENCRYPTED_CREDENTIALS>
|
@ -0,0 +1,32 @@
|
||||
FROM ruby:2.7.5-slim
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y \
|
||||
build-essential \
|
||||
libffi-dev \
|
||||
libgdbm-dev \
|
||||
libncurses5-dev \
|
||||
libreadline-dev \
|
||||
libssl-dev \
|
||||
libyaml-dev \
|
||||
zlib1g-dev \
|
||||
curl \
|
||||
libyaml-0-2 \
|
||||
libxml2-dev \
|
||||
libxslt-dev \
|
||||
libpq-dev
|
||||
|
||||
# Set environment variables.
|
||||
ENV HOME /var/app
|
||||
ENV RACK_ENV production
|
||||
# Define working directory.
|
||||
ADD . /var/app
|
||||
RUN bundle config set deployment 'true' \
|
||||
&& bundle config set without 'development test'
|
||||
RUN cd /var/app; bundle install
|
||||
|
||||
WORKDIR /var/app
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
CMD ["/bin/sh", "/var/app/bin/http"]
|
@ -0,0 +1,7 @@
|
||||
source 'https://rubygems.org'
|
||||
gem 'sinatra'
|
||||
gem 'sinatra-contrib'
|
||||
gem 'haml'
|
||||
gem 'puma'
|
||||
gem 'sidekiq'
|
||||
gem 'pg'
|
@ -0,0 +1,53 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
backports (3.21.0)
|
||||
connection_pool (2.2.2)
|
||||
haml (5.1.2)
|
||||
temple (>= 0.8.0)
|
||||
tilt
|
||||
multi_json (1.15.0)
|
||||
mustermann (1.1.1)
|
||||
ruby2_keywords (~> 0.0.1)
|
||||
nio4r (2.5.2)
|
||||
pg (1.2.3)
|
||||
puma (4.3.5)
|
||||
nio4r (~> 2.0)
|
||||
rack (2.2.2)
|
||||
rack-protection (2.0.8.1)
|
||||
rack
|
||||
redis (4.1.4)
|
||||
ruby2_keywords (0.0.2)
|
||||
sidekiq (6.0.7)
|
||||
connection_pool (>= 2.2.2)
|
||||
rack (~> 2.0)
|
||||
rack-protection (>= 2.0.0)
|
||||
redis (>= 4.1.0)
|
||||
sinatra (2.0.8.1)
|
||||
mustermann (~> 1.0)
|
||||
rack (~> 2.0)
|
||||
rack-protection (= 2.0.8.1)
|
||||
tilt (~> 2.0)
|
||||
sinatra-contrib (2.0.8.1)
|
||||
backports (>= 2.8.2)
|
||||
multi_json
|
||||
mustermann (~> 1.0)
|
||||
rack-protection (= 2.0.8.1)
|
||||
sinatra (= 2.0.8.1)
|
||||
tilt (~> 2.0)
|
||||
temple (0.8.2)
|
||||
tilt (2.0.10)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
haml
|
||||
pg
|
||||
puma
|
||||
sidekiq
|
||||
sinatra
|
||||
sinatra-contrib
|
||||
|
||||
BUNDLED WITH
|
||||
2.1.4
|
@ -0,0 +1,7 @@
|
||||
# README
|
||||
|
||||
[![Build Status](https://git2.imfiny.com/api/badges/OpenSource/sinatra_hello/status.svg)](https://git2.imfiny.com/OpenSource/sinatra_hello)
|
||||
|
||||
A simple, hello world ruby (sinatra) application.
|
||||
|
||||
You can also find it on [Docker hub](https://hub.docker.com/repository/docker/mcansky/sinatra_hello).
|
@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
echo "the port is : ${PORT}"
|
||||
bundle exec puma -t 5:5 -p ${PORT:-8080} -e ${RACK_ENV:-development}
|
@ -0,0 +1,2 @@
|
||||
require './hello'
|
||||
run Rack::URLMap.new('/' => SimpleApp)
|
@ -0,0 +1,85 @@
|
||||
require 'sinatra'
|
||||
require 'sinatra/custom_logger'
|
||||
require 'logger'
|
||||
|
||||
require 'sidekiq'
|
||||
require 'redis'
|
||||
require 'sidekiq/api'
|
||||
require 'haml'
|
||||
require 'pg'
|
||||
|
||||
# postgres://postgres:testpassword@pg-${APP_NAME}-${INSTANCE_NAME}/example?sslmode=disable
|
||||
module Db
|
||||
class Client
|
||||
def initialize
|
||||
db_url = ENV['DATABASE_URL'].gsub('postgres://', '')
|
||||
auth, host_db = db_url.split('@')
|
||||
@user, @password = auth.split(':')
|
||||
@host, db = host_db.split('/')
|
||||
@db = db.split('?')[0]
|
||||
end
|
||||
|
||||
def create_db
|
||||
conn.exec("CREATE DATABASE #{@db};")
|
||||
end
|
||||
|
||||
def create_table
|
||||
conn(@db).exec("CREATE TABLE entries (
|
||||
did SERIAL,
|
||||
name varchar(40) NOT NULL check (name <> '')
|
||||
);")
|
||||
end
|
||||
|
||||
def select_all
|
||||
conn(@db).exec("SELECT * from entries;")
|
||||
end
|
||||
|
||||
def insert_value
|
||||
conn(@db).exec("INSERT INTO entries (name) VALUES
|
||||
('bob'), ('mary')
|
||||
;")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def conn(db = nil)
|
||||
if db
|
||||
@conn ||= ::PG.connect(user: @user, password: @password, host: @host, dbname: db)
|
||||
else
|
||||
@conn ||= ::PG.connect(user: @user, password: @password, host: @host)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class SimpleApp < Sinatra::Base
|
||||
set :logger, Logger.new(STDOUT)
|
||||
|
||||
get '/' do
|
||||
haml "%h3 Hello Cat!"
|
||||
end
|
||||
|
||||
get '/db' do
|
||||
db_url = ENV['DATABASE_URL']
|
||||
auth, host_db = db_url.split('@')
|
||||
@user, @password = auth.split(':')
|
||||
@host, db = host_db.split('/')
|
||||
@db = db.split('?')[0]
|
||||
|
||||
client = Db::Client.new
|
||||
begin
|
||||
client.create_db
|
||||
rescue PG::DuplicateDatabase
|
||||
end
|
||||
client.create_table
|
||||
haml "%h2 Db created"
|
||||
end
|
||||
|
||||
get '/all' do
|
||||
client = Db::Client.new
|
||||
client.insert_value
|
||||
values = client.select_all
|
||||
|
||||
haml :all, locals: { data: values }
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue