Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
add gitlab-ci; travis-ci to deploy on GKE, Heroku
  • Loading branch information
hoatle committed Jul 7, 2017
1 parent 1f7d0cf commit ca822a6
Show file tree
Hide file tree
Showing 13 changed files with 466 additions and 0 deletions.
131 changes: 131 additions & 0 deletions .gitlab-ci.yml
@@ -0,0 +1,131 @@
image: docker:latest
#
services:
- docker:dind

variables:
# # see https://gitlab.com/gitlab-org/gitlab-ce/issues/17861#note_12991518
DOCKER_DRIVER: overlay

stages:
- build
- test
- deploy

variables:
HEROKU_USER_NAME: _
HEROKU_REGISTRY: registry.heroku.com

build-verify:
image: docker:latest
stage: build
before_script:
- apk add --no-cache py-pip
- pip install docker-compose
- docker-compose --version
# convert / to -, remove # character from docker tag name to make it a valid name
- export IMG_TAG=`if [ "$CI_BUILD_REF_NAME" == "master" ]; then echo "latest"; else echo $CI_BUILD_REF_NAME | sed -e 's/[\/]/-/g' | sed -e 's/[\#]//g'; fi`
- export DOCKER_IMAGE_PROD=$CI_REGISTRY_IMAGE:$IMG_TAG
- docker login -u "gitlab-ci-token" -p "$CI_BUILD_TOKEN" $CI_REGISTRY
- export CI_BUILD_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
script:
# build
- docker-compose -f docker-compose.prod.yml build --pull prod
- docker push $DOCKER_IMAGE_PROD

deploy-gcp-staging:
image: teracy/google-cloud-sdk
stage: deploy
before_script:
# convert / to -, remove # character from docker tag name to make it a valid name
- export IMG_TAG=`if [ "$CI_BUILD_REF_NAME" == "master" ]; then echo "latest"; else echo $CI_BUILD_REF_NAME | sed -e 's/[\/]/-/g' | sed -e 's/[\#]//g'; fi`
- export DOCKER_IMAGE_PROD=$CI_REGISTRY_IMAGE:$IMG_TAG
- export GCP_ACCOUNT=$GCP_ACCOUNT_STAGING
- export GCP_PROJECT_ID=$GCP_PROJECT_ID_STAGING
- export GCP_ZONE=$GCP_ZONE_STAGING
- export GCP_CLUSTER_NAME=$GCP_CLUSTER_NAME_STAGING
- export HELM_RELEASE_NAME=$IMG_TAG-${HELM_PROJECT_NAMESPACE:-$CI_PROJECT_NAMESPACE}-nhw
- export HELM_CHART=helm-charts/nodejs-hello-world
- export HELM_IMAGE_REPOSITORY=$CI_REGISTRY_IMAGE
- export HELM_IMAGE_TAG=$IMG_TAG
- export HELM_IMAGE_PULL_POLICY=Always
- export HELM_IMAGE_LAST_DEPLOYED=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
#- docker login -u "gitlab-ci-token" -p "$CI_BUILD_TOKEN" $CI_REGISTRY
- echo $GCP_KEY_FILE_STAGING | base64 --decode > /tmp/gcp_key_file.json
script:
- sh scripts/setup_gcp.sh
- sh scripts/deploy_gcp.sh
after_script:
- rm /tmp/gcp_key_file.json
environment: staging
only:
- develop
allow_failure: true # for downstream failure
when: on_success


deploy-gcp-prod:
image: teracy/google-cloud-sdk
stage: deploy
before_script:
# convert / to -, remove # character from docker tag name to make it a valid name
- export IMG_TAG=`if [ "$CI_BUILD_REF_NAME" == "master" ]; then echo "latest"; else echo $CI_BUILD_REF_NAME | sed -e 's/[\/]/-/g' | sed -e 's/[\#]//g'; fi`
- export DOCKER_IMAGE_PROD=$CI_REGISTRY_IMAGE:$IMG_TAG
- export GCP_ACCOUNT=$GCP_ACCOUNT_PROD
- export GCP_PROJECT_ID=$GCP_PROJECT_ID_PROD
- export GCP_ZONE=$GCP_ZONE_PROD
- export GCP_CLUSTER_NAME=$GCP_CLUSTER_NAME_PROD
- export HELM_RELEASE_NAME=$IMG_TAG-${HELM_PROJECT_NAMESPACE:-$CI_PROJECT_NAMESPACE}-nhw
- export HELM_CHART=helm-charts/nodejs-hello-world
- export HELM_IMAGE_REPOSITORY=$CI_REGISTRY_IMAGE
- export HELM_IMAGE_TAG=$IMG_TAG
- export HELM_IMAGE_PULL_POLICY=Always
- export HELM_IMAGE_LAST_DEPLOYED=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
#- docker login -u "gitlab-ci-token" -p "$CI_BUILD_TOKEN" $CI_REGISTRY
- echo $GCP_KEY_FILE_PROD | base64 --decode > /tmp/gcp_key_file.json
script:
- sh scripts/setup_gcp.sh
- sh scripts/deploy_gcp.sh
after_script:
- rm /tmp/gcp_key_file.json
environment: prod
only:
- master
allow_failure: true # for downstream failure
when: on_success


deploy-heroku-staging:
stage: deploy
before_script:
# convert / to -, remove # character from docker tag name to make it a valid name
- export IMG_TAG=`if [ "$CI_BUILD_REF_NAME" == "master" ]; then echo "latest"; else echo $CI_BUILD_REF_NAME | sed -e 's/[\/]/-/g' | sed -e 's/[\#]//g'; fi`
- export DOCKER_IMAGE=$CI_REGISTRY_IMAGE:$IMG_TAG
- export HEROKU_IMAGE=$HEROKU_REGISTRY/$HEROKU_APP_NAME_STAGING/web
- docker login -u "gitlab-ci-token" -p "$CI_BUILD_TOKEN" $CI_REGISTRY
script:
- echo "login into Heroku Docker registry"
- docker login -u "$HEROKU_USER_NAME" -p "$HEROKU_API_KEY_STAGING" $HEROKU_REGISTRY
- sh scripts/deploy_heroku.sh
environment: staging
only:
- develop
allow_failure: true # for downstream failure
when: on_success

deploy-heroku-prod:
stage: deploy
before_script:
# convert / to -, remove # character from docker tag name to make it a valid name
- export IMG_TAG=`if [ "$CI_BUILD_REF_NAME" == "master" ]; then echo "latest"; else echo $CI_BUILD_REF_NAME | sed -e 's/[\/]/-/g' | sed -e 's/[\#]//g'; fi`
- export DOCKER_IMAGE=$CI_REGISTRY_IMAGE:$IMG_TAG
- export HEROKU_IMAGE=$HEROKU_REGISTRY/$HEROKU_APP_NAME_PROD/web
- docker login -u "gitlab-ci-token" -p "$CI_BUILD_TOKEN" $CI_REGISTRY
script:
- docker login -u "$HEROKU_USER_NAME" -p "$HEROKU_API_KEY_PROD" $HEROKU_REGISTRY
- sh scripts/deploy_heroku.sh
environment: prod
only:
- master
allow_failure: true # for downstream failure
when: on_success
89 changes: 89 additions & 0 deletions .travis.yml
@@ -0,0 +1,89 @@
sudo: required
services:
- docker
env:
global:
CI_BUILD_TIME: $(date -u +"%Y-%m-%dT%H:%M:%SZ")
CI_BUILD_ID: $TRAVIS_BUILD_ID
CI_BUILD_REF: $TRAVIS_COMMIT
CI_BUILD_REF_NAME: $TRAVIS_BRANCH
CI_BUILD_NUMBER: $TRAVIS_BUILD_NUMBER
CI_BUILDER: travis-ci
CI_PROJECT_NAME: $TRAVIS_REPO_SLUG
HEROKU_USER_NAME: _
HEROKU_REGISTRY: registry.heroku.com

before_install:
# install the latest docker and docker-compose versions
- sudo apt-get remove docker docker-engine
- sudo curl -sSL https://get.docker.com/ | sh
- sudo rm /usr/local/bin/docker-compose
# the latest docker-compose version
- export DOCKER_COMPOSE_VERSION=$(curl -s https://api.github.com/repos/docker/compose/releases/latest | grep 'tag_name' | cut -d\" -f4)
- curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose
- chmod +x docker-compose
- sudo mv docker-compose /usr/local/bin
- docker --version
- docker-compose --version
# install google-cloud-sdk
# clean up existing gcloud pre-installed by travis-ci
- sudo rm -rf /usr/bin/git-credential-gcloud.sh /usr/bin/bq /usr/bin/gcloud /usr/bin/gsutil
# Make sure gcloud command is on our PATH
- export PATH=$PATH:${HOME}/google-cloud-sdk/bin
- export CLOUDSDK_CORE_DISABLE_PROMPTS=1
# If the SDK is not already cached, download it and unpack it
- if [ ! -d ${HOME}/google-cloud-sdk ]; then
curl https://sdk.cloud.google.com | bash;
fi
- gcloud version
- gcloud components install kubectl
# install helm
- curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get | bash
- helm version --client
before_script:
- export CI_REGISTRY_IMAGE=$DOCKER_USER/$DOCKER_REPO
- export IMG_TAG=`if [ "$TRAVIS_BRANCH" == "master" ]; then echo "latest"; else echo $TRAVIS_BRANCH | sed -e 's/[\/]/-/g' | sed -e 's/[\#]//g'; fi`
- export DOCKER_IMAGE_PROD=$CI_REGISTRY_IMAGE:$IMG_TAG
- export CI_PROJECT_NAMESPACE=`echo $CI_PROJECT_NAME | cut -d"/" -f1`;
script:
- docker-compose -f docker-compose.prod.yml build --pull prod;
after_success:
- docker login -u=$DOCKER_USERNAME -p=$DOCKER_PASSWORD
- docker push $DOCKER_IMAGE_PROD
- if [[ "$TRAVIS_BRANCH" == "develop" ]]; then
export GCP_PROJECT_ID=$GCP_PROJECT_ID_STAGING;
export GCP_ZONE=$GCP_ZONE_STAGING;
export GCP_CLUSTER_NAME=$GCP_CLUSTER_NAME_STAGING;
export HELM_RELEASE_NAME=$IMG_TAG-${HELM_PROJECT_NAMESPACE:-$CI_PROJECT_NAMESPACE}-nhw;
export HELM_CHART=helm-charts/nodejs-hello-world;
export HELM_IMAGE_REPOSITORY=$CI_REGISTRY_IMAGE;
export HELM_IMAGE_TAG=$IMG_TAG;
export HELM_IMAGE_PULL_POLICY=Always;
export HELM_IMAGE_LAST_DEPLOYED=$(date -u +"%Y-%m-%dT%H:%M:%SZ");
echo $GCP_KEY_FILE_STAGING | base64 --decode > /tmp/gcp_key_file.json;
export DOCKER_IMAGE=$DOCKER_IMAGE_PROD;
export HEROKU_IMAGE=$HEROKU_REGISTRY/$HEROKU_APP_NAME_STAGING/web;
export HEROKU_API_KEY=$HEROKU_API_KEY_STAGING;
fi
- if [[ "$TRAVIS_BRANCH" == "master" ]]; then
export GCP_PROJECT_ID=$GCP_PROJECT_ID_PROD;
export GCP_ZONE=$GCP_ZONE_PROD;
export GCP_CLUSTER_NAME=$GCP_CLUSTER_NAME_PROD;
export HELM_RELEASE_NAME=$IMG_TAG-${HELM_PROJECT_NAMESPACE:-$CI_PROJECT_NAMESPACE}-nhw;
export HELM_CHART=helm-charts/nodejs-hello-world;
export HELM_IMAGE_REPOSITORY=$CI_REGISTRY_IMAGE;
export HELM_IMAGE_TAG=$IMG_TAG;
export HELM_IMAGE_PULL_POLICY=Always;
export HELM_IMAGE_LAST_DEPLOYED=$(date -u +"%Y-%m-%dT%H:%M:%SZ");
echo $GCP_KEY_FILE_PROD | base64 --decode > /tmp/gcp_key_file.json;
export DOCKER_IMAGE=$DOCKER_IMAGE_PROD;
export HEROKU_IMAGE=$HEROKU_REGISTRY/$HEROKU_APP_NAME_PROD/web;
export HEROKU_API_KEY=$HEROKU_API_KEY_PROD;
fi
- if [[ "$TRAVIS_BRANCH" == "master" ]] || [[ "$TRAVIS_BRANCH" == "develop" ]]; then
sh scripts/setup_gcp.sh;
sh scripts/deploy_gcp.sh;
docker login -u "$HEROKU_USER_NAME" -p "$HEROKU_API_KEY" $HEROKU_REGISTRY;
sh scripts/deploy_heroku.sh;
fi
- rm -rf /tmp/gcp_key_file.json
21 changes: 21 additions & 0 deletions helm-charts/nodejs-hello-world/.helmignore
@@ -0,0 +1,21 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
4 changes: 4 additions & 0 deletions helm-charts/nodejs-hello-world/Chart.yaml
@@ -0,0 +1,4 @@
apiVersion: v1
description: A Helm chart for Kubernetes
name: nodejs-hello-world
version: 0.1.0
17 changes: 17 additions & 0 deletions helm-charts/nodejs-hello-world/templates/NOTES.txt
@@ -0,0 +1,17 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.hostname }}
http://{{- .Values.ingress.hostname }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get svc -w {{ template "fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:{{ .Values.service.externalPort }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl port-forward $POD_NAME 8080:{{ .Values.service.externalPort }}
{{- end }}
16 changes: 16 additions & 0 deletions helm-charts/nodejs-hello-world/templates/_helpers.tpl
@@ -0,0 +1,16 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}

{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
*/}}
{{- define "fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
46 changes: 46 additions & 0 deletions helm-charts/nodejs-hello-world/templates/deployment.yaml
@@ -0,0 +1,46 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: {{ template "fullname" . }}
labels:
app: {{ template "name" . }}
chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
replicas: {{ .Values.replicaCount }}
template:
metadata:
labels:
app: {{ template "name" . }}
release: {{ .Release.Name }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
env:
- name: PORT
value: {{ .Values.service.internalPort | quote }}
# for rolling updates without downtime
# see: https://github.com/kubernetes/kubernetes/issues/33664#issuecomment-292895327
- name: LAST_DEPLOYED
value: {{ .Values.image.lastDeployed | quote }}
ports:
- containerPort: {{ .Values.service.internalPort }}
livenessProbe:
httpGet:
path: /
port: {{ .Values.service.internalPort }}
readinessProbe:
httpGet:
path: /
port: {{ .Values.service.internalPort }}
resources:
{{ toYaml .Values.resources | indent 12 }}
{{- if .Values.nodeSelector }}
nodeSelector:
{{ toYaml .Values.nodeSelector | indent 8 }}
{{- end }}
imagePullSecrets:
- name: registry.gitlab.com
32 changes: 32 additions & 0 deletions helm-charts/nodejs-hello-world/templates/ingress.yaml
@@ -0,0 +1,32 @@
{{- if .Values.ingress.enabled -}}
{{- $serviceName := include "fullname" . -}}
{{- $servicePort := .Values.service.externalPort -}}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: {{ template "fullname" . }}
labels:
app: {{ template "name" . }}
chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
{{- range $key, $value := .Values.ingress.annotations }}
{{ $key }}: {{ $value | quote }}
{{- end }}
spec:
rules:
{{- range $host := .Values.ingress.hosts }}
- host: {{ $host }}
http:
paths:
- path: /
backend:
serviceName: {{ $serviceName }}
servicePort: {{ $servicePort }}
{{- end -}}
{{- if .Values.ingress.tls }}
tls:
{{ toYaml .Values.ingress.tls | indent 4 }}
{{- end -}}
{{- end -}}
19 changes: 19 additions & 0 deletions helm-charts/nodejs-hello-world/templates/service.yaml
@@ -0,0 +1,19 @@
apiVersion: v1
kind: Service
metadata:
name: {{ template "fullname" . }}
labels:
app: {{ template "name" . }}
chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.externalPort }}
targetPort: {{ .Values.service.internalPort }}
protocol: TCP
name: {{ .Values.service.name }}
selector:
app: {{ template "name" . }}
release: {{ .Release.Name }}

0 comments on commit ca822a6

Please sign in to comment.