前言

最近了解到很多团队会用到Kubernetes来统一管理应用. 当然. 我们公司也不例外。所以后续会对 各种类型的应用上 Kubernetes 做一些分享。

统一部署Kubernetes的好处.

可以对所有应用统一管理. 融灾. 迁移...

举个🌰. 当我们在阿里云深圳区A的k8s集群因为各种原因出现服务故障 无法正常提供服务后. 我们可以快速在 上海区 或者 其他云例如 Azure 购买服务器然后通过ansible脚本一键部署k8s集群. 在最快的时间内恢复服务.

实施

SPA 应用因为完全没有涉及到node 跟 服务端. 我们都不需要用到 Service, 只需要一个 Ingress 跟 CDN 存储, 我们可以直接将每个版本的资源上传到CDN. 然后通过 Ingress 转发到 CDN 到每个版本.

image.png

我们先创建一个 helm 项目.
helm 是一个k8s的项目管理工具. 这里我们不讨论. google关于这个的资料.

helm create frontendexamples

### 因为我们只需要用到 ingress 所以删除其他多余到服务.
rm deployment.yaml service.yaml serviceaccount.yaml

然后编辑 ingress.yaml 成我们需要到样子. 根据前端到静态资源来转发并且根据版本号做缓存

{{- $ingress := .Values.ingress }}
{{- $top := . -}}
{{- if $ingress.enabled }}
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: {{ include "frontendexamples.fullname" . }}-{{ $ingress.name }}
  labels:
    {{- include "frontendexamples.labels" . | nindent 4 }}
  {{- with $ingress.annotations }}
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/configuration-snippet: |
      ### 默认重定向到首页
      return 302 $scheme://$host/index.html;
    nginx.ingress.kubernetes.io/server-snippet: |
        location = / {
          return 302 $scheme://$host/index.html;
        }
      
        {{- $cdnHost := $top.Values.cdnHost -}}
        {{- $cdnPrefix := $top.Values.cdnPrefix -}}
        {{- range $top.Values.htmlList -}}

        location = {{ . }} {
          rewrite ^(.*)$ /{{ $cdnPrefix }}{{ . }} break; 
          proxy_pass {{ $cdnHost }};
          proxy_buffering on;
          proxy_buffer_size  128k;
          proxy_buffers 100  128k;
          proxy_cache        auth_cache;
          proxy_cache_key {{ $cdnPrefix }};
          proxy_cache_valid      200  1d;
          proxy_cache_use_stale  error timeout invalid_header updating
                                 http_500 http_502 http_503 http_504;
        }
        {{- end -}}
    {{- toYaml . | nindent 4 }}
  {{- end }}
spec:
  rules:
  {{- range $ingress.hosts }}
    - host: {{ .host | quote }}
      http:
        paths:
        {{- range .paths }}
          - path: {{ . }}
            backend:
              serviceName: none
              servicePort: 80
        {{- end }}
  {{- end }}
{{- end }}

然后. 我们写一个前端编译然后生成对应静态资源文件(index.html)的部署bash脚本.

用来生成一份helm values文件

# Default values for frontendexamples.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
cdnHost: "https://bg-stage.wkcoding.com/"
cdnPrefix: "wixland/pro/2031"
htmlList:
    - /index.html

build -> upload cdn -> generate html values

scripts/deploy.sh

#!/bin/bash

set -o errexit
set -o nounset
set -o pipefail

### get project dir
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do
  DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
  SOURCE="$(readlink "$SOURCE")"
  [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE"
done
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"

readonly PROJECT_ROOT="$(dirname $DIR)"
readonly BUILDOUT_DIR=${BUILDOUT_DIR:-"$PROJECT_ROOT/build"}
readonly BUCKET_HOST=${BUCKET_HOST:-""}
readonly APPLICATION_NAME=${APPLICATION_NAME:-"frontendexamples"}
readonly RESOURCES_PREFIX=${RESOURCES_PREFIX:-"wixland/pro"}
readonly BUCKET=${BUCKET:-"bp-stage"}
readonly QINIU_AK=${QINIU_AK:-""}
readonly QINIU_SK=${QINIU_SK:-""}

cd $PROJECT_ROOT
VERSION=""

### application version
get_current_version() {
    if [[ -z "$VERSION" ]]; then
        echo -e "Enter version:" >&2
        read -r VERSION
    fi
    echo $VERSION;
    #echo $(date +%Y%m%d%H%M%S)
}

### build code
build() {
    echo "building..."
    version=${1:-""}
    appVersion=${version} appResourcesPrefix=${RESOURCES_PREFIX} cdnHost=${BUCKET_HOST} yarn build
}

### upload builded code to qiniu cdn
upload() {
    echo "uploading..."
    version=${1:-""}
    /Users/albert/code/github/qiniu-uploader/bin/qiniu-upload.js -r 1 -es 1000000 \
    --verbose -b ${BUCKET} \
    -p "${RESOURCES_PREFIX}/${version}" \
    --base ./build --ak ${QINIU_AK} --sk ${QINIU_SK} 'build/**'
}

### Auto install [qiniu2uploader](https://github.com/work4fun/qiniu-uploader)
### An small resume upload qiniu tools
dectect_autoinstall_qiniu2uploader() {
    if ! [ -x "$(command -v qiniu-upload)" ]; then
        yarn global add -g qiniu2uploader
    fi
}

dectect_autoinstall_qiniu2uploader

version=$(get_current_version)

build $version
upload $version


### Generate helm values.
### Examples:
### cdnHost: "http://bg-stage.wkcoding.com/"
### cdnPrefix: "wixland/pro/20000"
### htmlList: 
###  - /index.html
###
htmlList=""
for html in $(find "$BUILDOUT_DIR" -type f -name "*.html")
do
    ### Replace string
    ### ${content/search/replace}
    html=${html/$BUILDOUT_DIR/''}
    htmlList="- $html
  $htmlList
"
done

cat << EOF > "$PROJECT_ROOT/docker/$APPLICATION_NAME/html.yaml"
# Default values for $APPLICATION_NAME.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
cdnHost: "https:$BUCKET_HOST"
cdnPrefix: "$RESOURCES_PREFIX/$version"
htmlList: 
  $htmlList
EOF

### deploy with helm
helm upgrade $APPLICATION_NAME ./docker/$APPLICATION_NAME --install --values ./docker/$APPLICATION_NAME/html.yaml

上面都完成后我们只需要运行. 就可以完成部署了.

bash ./scripts/deploy.sh

缺点

  • 依赖 ingress-nginx
  • 依赖单点cdn存储. 如果cdn挂了集群也挂了.
  • 缺少对cdn的监控

后续

  • 实现多cdn上传
  • 实现cdn心跳检测. 自动切换主/备 CDN

以上源码都在 https://github.com/work4fun/e...


Albert
104 声望2 粉丝

Self-Taught / Backend Engineer / Lifelong learner/ Devops / Automation enthusiast / Productivity fan/ full-stack


« 上一篇
认识vscode(三)