Skip to content

Commit

Permalink
🧁feat: added the static site chart 🧁 (#24)
Browse files Browse the repository at this point in the history
🧁 Created a deploy engine for deploying static site onto a Kubernetes cluster with auto-updating capabilities 🧁
  • Loading branch information
jijiechen authored Apr 20, 2020
1 parent 9fa4031 commit 7c36aad
Show file tree
Hide file tree
Showing 10 changed files with 563 additions and 0 deletions.
9 changes: 9 additions & 0 deletions charts/static-site/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
apiVersion: v2
name: static-site
description: A Helm chart for deploying a static-site with auto-updating
type: application
version: 0.0.3
appVersion: 1.17.9-alpine
home: https://github.com/rht-labs/helm-charts
maintainers:
- name: jijiechen
27 changes: 27 additions & 0 deletions charts/static-site/README-zh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@

## 在 Kubernetes 上部署的可自动更新的静态网站

此项目包含一个 helm chart,它支持向 Kubernetes 部署一个静态网站,并根据 Git 仓库中的最新变更,自动更新网站。

### 用法

```sh
helm install my-cool-site ./ --set "repo.location=https://git-location-of-your-static-site"
```

### 支持的 Helm 设置项

下表列出了这个 Helm Chart 所支持的各项设置及其默认值:

| 参数 | 描述 | 默认值 | 是否必填 |
| -------------------- | ------------------------------------------------- | --------------- | ----------------- |
| `repo.location` | 存储静态网站源代码的 Git 仓库地址的 HTTP(s) 地址 | ||
| `repo.branch` | 要部署的分支名称 | `master` ||
| `repo.credential.username` | Git 仓库的用户名 | ||
| `repo.credential.password` | Git 仓库的密码 | ||
| `site.enableDirectoryListing` | 是否启用目录浏览功能 | `false` ||
| `replicas` | 部署时,要生成的副本数目 | `2` ||
| `autoUpdateCron` | 用以设定检测自动更新频率的 CRON 表达式 | `* * * * *`, 即每分钟检查 ||



28 changes: 28 additions & 0 deletions charts/static-site/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

[查看中文说明文档](README-zh.md)

## Static Site Deployment with Automatic Updating on Kubernetes

This is a helm chart supporting deploying a static website onto Kubernetes and enable auto-polling to its Git repository.

### Usage

```sh
helm install my-cool-site ./ --set "repo.location=https://git-location-of-your-static-site"
```

### Supported Helm Settings

The following table lists the settings of the chart and their default values.

| Parameter | Description | Default | Required |
| -------------------- | ---------------------------------------------------------- | --------------- | ----------------- |
| `repo.location` | HTTP(s) based URL of your git repository that stores source of the site | | Y |
| `repo.branch` | Name of git branch you want to deploy | `master` | N |
| `repo.credential.username` | Username to of the git repository | | N |
| `repo.credential.password` | Password to of the git repository | | N |
| `site.enableDirectoryListing` | Whether enable directory listing for the site | `false` | N |
| `replicas` | Number of replicas of the deployment | `2` | N |
| `autoUpdateCron` | The CRON expression scheduling the auto update polling job | `* * * * *`, which means every minute | N |


7 changes: 7 additions & 0 deletions charts/static-site/alpine-curl-git.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FROM alpine/git:v2.24.1
RUN apk add --no-cache curl

ENTRYPOINT ["/bin/sh"]

# docker build . -f ./alpine-curl-git.Dockerfile -t jijiechen/alpine-curl-git:v2.24.1
# https://hub.docker.com/r/jijiechen/alpine-curl-git
50 changes: 50 additions & 0 deletions charts/static-site/templates/_helpers.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@

{{/*
Return the proper Storage Class
*/}}
{{- define "tmpl.storageClass" -}}
{{- if .Values.persistence.storage.storageClass -}}
{{- if (eq "-" .Values.persistence.storage.storageClass) -}}
{{- printf "storageClassName: \"\"" -}}
{{- else }}
{{- printf "storageClassName: %s" .Values.persistence.storage.storageClass -}}
{{- end -}}
{{- end -}}
{{- end -}}


{{/*
Return the template of poller/updater pod
*/}}
{{- define "tmpl.pollerPodSpec" -}}
restartPolicy: Never
serviceAccountName: {{ .Release.Name }}-redeployer
volumes:
- name: poller-script
configMap:
name: static-site-{{ .Release.Name }}-poller-script
defaultMode: 0777
containers:
- name: poller
image: jijiechen/alpine-curl-git:v2.24.1
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /var/poller/
name: poller-script
command: ["/bin/sh"]
args:
- /var/poller/poll.sh
env:
- name: REPO_URL
value: {{ .Values.repo.location }}
- name: BRANCH
value: {{ .Values.repo.branch }}
resources:
limits:
cpu: 200m
memory: "200Mi"
requests:
cpu: 50m
memory: "100Mi"
{{- end -}}

138 changes: 138 additions & 0 deletions charts/static-site/templates/configmap.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: static-site-{{ .Release.Name }}-config
labels:
app: static-site
site: {{ .Release.Name }}
data:
nginx.conf: |
user nginx;
worker_processes auto;
error_log /tmp/log/nginx/error.log warn;
pid /tmp/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /tmp/log/nginx/access.log main;
client_body_temp_path /tmp/client_temp;
proxy_temp_path /tmp/proxy_temp_path;
fastcgi_temp_path /tmp/fastcgi_temp;
uwsgi_temp_path /tmp/uwsgi_temp;
scgi_temp_path /tmp/scgi_temp;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
gzip on;
include /etc/nginx/conf.d/*.conf;
}
default.conf: |
server {
listen 8080;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
location / {
absolute_redirect off;
{{- if .Values.site.enableDirectoryListing }}
autoindex on;
{{- end }}
root /usr/share/nginx/html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
clone.sh: |
#!/bin/sh
set -e
REPO_URL='{{ .Values.repo.location }}'
{{- if and .Values.repo.credential.username .Values.repo.credential.password }}
echo 'exec echo $GIT_PASSWORD' > /tmp/git-askpass.sh
chmod +x /tmp/git-askpass.sh
export GIT_ASKPASS=/tmp/git-askpass.sh
if [ ! -z "${REPO_URL##*@*}" ] ; then
REPO_URL=$(echo $REPO_URL | sed 's;//;//{{ .Values.repo.credential.username }}@;')
fi
{{- end }}
INSIDE_TREE=$(git rev-parse --is-inside-work-tree 2>/dev/null || true)
if [ -z "$INSIDE_TREE" ]; then
git init .
fi
git config remote.origin.url $REPO_URL
BRANCH={{ .Values.repo.branch }}
CURRENT=$(git rev-parse --verify HEAD 2>/dev/null || true)
if [ "$CURRENT" != "$GIT_REVISION" ]; then
git fetch --no-tags --progress -- $REPO_URL +refs/heads/$BRANCH:refs/remotes/origin/$BRANCH
git config advice.detachedHead false
git checkout -f $GIT_REVISION
git branch -D $BRANCH 2>/dev/null || true
git checkout -b $BRANCH $GIT_REVISION
fi
git reset --hard
git clean -fdx
# Running at /source
cp -R ./ /website
rm -rf /website/.git
129 changes: 129 additions & 0 deletions charts/static-site/templates/cronjob.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
{{- if .Values.autoUpdateCron }}

apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: static-site-{{ .Release.Name }}-poller
labels:
app: static-site
site: {{ .Release.Name }}
spec:
schedule: "{{ .Values.autoUpdateCron }}"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 1
failedJobsHistoryLimit: 1
jobTemplate:
spec:
backoffLimit: 0
template:
spec:
{{ include "tmpl.pollerPodSpec" . | indent 10 }}

---
{{- end }}

apiVersion: v1
kind: ConfigMap
metadata:
name: static-site-{{ .Release.Name }}-poller-script
labels:
app: static-site
site: {{ .Release.Name }}
data:
poll.sh: |-
#!/bin/sh
set -e
if [ -z "$REPO_URL" ]; then
exit 0
fi
K8S_URL=https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT_HTTPS
NAMESPACE=$(cat /run/secrets/kubernetes.io/serviceaccount/namespace)
TOKEN=$(cat /run/secrets/kubernetes.io/serviceaccount/token)
CACERT=/run/secrets/kubernetes.io/serviceaccount/ca.crt
{{- if .Values.persistence.enabled }}
RES_TYPE=statefulset
{{- else }}
RES_TYPE=deployment
{{- end }}
CURRENT=$(curl --cacert $CACERT -H "Authorization: Bearer $TOKEN" $K8S_URL/apis/apps/v1/namespaces/$NAMESPACE/${RES_TYPE}s/static-site-{{ .Release.Name }} 2>/dev/null | grep '"git_revision"' | tail -n 1 | cut -f 4 -d '"')
LATEST=$(git ls-remote $REPO_URL | grep refs/heads/$BRANCH | awk '{print $1}')
if [ "$LATEST" != "$CURRENT" ] ; then
echo "Redeploying static-site-{{ .Release.Name }}: the current ${RES_TYPE} $CURRENT has expired, as the latest revision is $LATEST"
PATCH_REPLICA=
if [ "$CURRENT" = "pending-init" ]; then
PATCH_REPLICA='"replicas": {{ .Values.replicas }},'
fi
PATCH="{\"spec\": { $PATCH_REPLICA \"template\": {\"metadata\": { \"labels\": { \"git_revision\": \"$LATEST\"}}}}}"
curl --cacert $CACERT -X PATCH -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/strategic-merge-patch+json' --data "$PATCH" \
$K8S_URL/apis/apps/v1/namespaces/$NAMESPACE/${RES_TYPE}s/static-site-{{ .Release.Name }}
else
echo "No change: static-site-{{ .Release.Name }} stayed the same as current ${RES_TYPE} $CURRENT"
fi
---

apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ .Release.Name }}-redeployer
labels:
app: static-site
site: {{ .Release.Name }}

---

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ .Release.Name }}-static-site-updater
rules:
- apiGroups: ["extensions", "apps"]
resources: ["deployments", "statefulsets"]
verbs: ["get", "patch"]

---

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ .Release.Name }}_redeployer
labels:
app: static-site
site: {{ .Release.Name }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{ .Release.Name }}-static-site-updater
subjects:
- kind: ServiceAccount
name: {{ .Release.Name }}-redeployer


---

apiVersion: batch/v1
kind: Job
metadata:
name: static-site-{{ .Release.Name }}-first-poller
labels:
app: static-site
site: {{ .Release.Name }}
annotations:
helm.sh/hook: post-install
helm.sh/hook-delete-policy: "before-hook-creation,hook-succeeded"
spec:
activeDeadlineSeconds: 600
completions: 1
parallelism: 1
template:
spec:
{{ include "tmpl.pollerPodSpec" . | indent 6 }}
Loading

0 comments on commit 7c36aad

Please sign in to comment.