Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
with
466 additions
and 0 deletions.
- +131 −0 .gitlab-ci.yml
- +89 −0 .travis.yml
- +21 −0 helm-charts/nodejs-hello-world/.helmignore
- +4 −0 helm-charts/nodejs-hello-world/Chart.yaml
- +17 −0 helm-charts/nodejs-hello-world/templates/NOTES.txt
- +16 −0 helm-charts/nodejs-hello-world/templates/_helpers.tpl
- +46 −0 helm-charts/nodejs-hello-world/templates/deployment.yaml
- +32 −0 helm-charts/nodejs-hello-world/templates/ingress.yaml
- +19 −0 helm-charts/nodejs-hello-world/templates/service.yaml
- +37 −0 helm-charts/nodejs-hello-world/values.yaml
- +20 −0 scripts/deploy_gcp.sh
- +7 −0 scripts/deploy_heroku.sh
- +27 −0 scripts/setup_gcp.sh
@@ -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 |
@@ -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 |
@@ -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 |
@@ -0,0 +1,4 @@ | ||
apiVersion: v1 | ||
description: A Helm chart for Kubernetes | ||
name: nodejs-hello-world | ||
version: 0.1.0 |
@@ -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 }} |
@@ -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 -}} |
@@ -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 |
@@ -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 -}} |
@@ -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 }} |
Oops, something went wrong.