Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

k8s 使用 Sidecar 容器设计模式来部署前端应用 #47

Open
lqshow opened this issue Nov 5, 2018 · 2 comments
Open

k8s 使用 Sidecar 容器设计模式来部署前端应用 #47

lqshow opened this issue Nov 5, 2018 · 2 comments

Comments

@lqshow
Copy link
Owner

lqshow commented Nov 5, 2018

Overview

目前所有前端产品的部署流程是这样的,首先由前端项目打包提供纯静态文件,然后基于 nginx 实现静态网页的部署。

现在的做法是将静态文件和 nginx 定制在一个镜像内,由于打包需要 nodejs 的环境,所以最终生产的镜像根据依赖的不同一般都达到了1G 以上。

目前升级 app 的内容,哪怕只更改一个 app 的配置或者调整 nginx 的配置,都需要重新制作一个新的镜像发布,这样的流程非常麻烦。即使事先将配置做成卷映射,但是镜像依然巨大。

Sidecar pattern

sidecar 指的就是我们可以在一个 Pod 中,启动一个或多个辅助容器,来完成一些独立于主进程(主容器)之外的工作。

它主要利用在同一 Pod 中的容器可以共享存储空间的能力。

Frontend Deployment

根据 Sidecar 的容器设计模式,我们可以很容易想到,这里 nginx 应该作为主容器,前端项目作为辅助容器,只需负责提供静态文件即可。

这样部署有以下3个好处

  1. 辅助容器可以利用 Docker 多阶段构建来生产出更小的镜像,因为只提供静态文件,使部署更快。(将原先将近1G 的镜像缩减到10M左右)
  2. 将 nginx 主容器独立出来,后续升级配置可以统一管控。
  3. 解决了 app 中静态文件 和 nginx 之间的耦合关系,做到了每个容器职责分明。

Step 1: Frontend Dockerfile

通过多阶段构建生产 mini 镜像

FROM node:latest as builder

WORKDIR /data/project
COPY ./ ./
RUN npm install && npm run build

FROM alpine

WORKDIR /project/dist
COPY --from=builder /data/project/dist  ./
docker build -t lqshow/app-test .

Step 2: Create configmap for Nginx configuration

将 nginx 的配置通过 Configmap 方式注入到容器

kind: ConfigMap
apiVersion: v1
metadata:
  name: nginx-config
data:
  nginx.conf: |
    user              nginx;
    worker_processes  1;
    error_log  /var/log/nginx/error.log;
    pid        /var/run/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  /var/log/nginx/access.log  main;
        sendfile        on;

        keepalive_timeout  65;

        # Load config files from the /etc/nginx/conf.d directory
        # The default server is in conf.d/default.conf
        include /etc/nginx/conf.d/*.conf;
    }
  default.conf: |
    server {
        listen       80;
        server_name  localhost;
        gzip on;
        gzip_comp_level 9;
        gzip_vary on;
        gzip_static on;
        gzip_types text/plain application/x-javascript text/css application/xml application/json application/javascript application/x-httpd-php image/jpeg image/gif image/png image/svg+xml xml/svg;
        
        # Set nginx to serve files from the shared volume
        root   /usr/share/nginx/data/project;

        location / {
            try_files $uri /index.html;
        }
    }

Step 3: Create deployment

在这个 Pod 模板中,定义了两个容器

  1. lqshow/app-test(这个镜像很简单,只提供静态文件,将文件放在 /var/www/html 下)
  2. nginx:1.15.2(标准的 nginx 镜像)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
      
  template:
    metadata:
      labels:
        app: nginx
    spec:
      initContainers:
      - name: app-container
        image: lqshow/app-test
        imagePullPolicy: Always
        command: ["/bin/sh", "-c", "mkdir -p /var/www/html && cp -r /project/dist/. /var/www/html"]
        volumeMounts:
          - name: shared-files
            mountPath: /var/www/html
            
      containers:
      - name: nginx-container
        image: nginx:1.15.2
        imagePullPolicy: Always
        ports:
          - containerPort: 80
        volumeMounts:
          - name: shared-files
            mountPath: /usr/share/nginx/data/project
          - name: nginx-config-volume
            mountPath: /etc/nginx/nginx.conf
            subPath: nginx.conf
          - name: nginx-config-volume
            mountPath: /etc/nginx/conf.d/default.conf
            subPath: default.conf
           
      volumes:
        # 共享文件卷,用于共享 app 静态文件
        - name: shared-files
          emptyDir: {}

        # ConfigMap 向 ngnix 容器注入配置信息
        - name: nginx-config-volume
          configMap:
            name: nginx-config

Reference

@sweetpotatoman
Copy link

你这样挂载 nginx 配置,subPath 的方式,不会冲掉 /etc/nginx 里的东西,但是 configmap 不会热更新,且你这个也没有做到 configmap 更新后实现 nginx reload~

@lqshow
Copy link
Owner Author

lqshow commented Dec 27, 2019

@sweetpotatoman 对的,这个 demo 中的 nginx 不会自动做 reload 的。

nginx 容器中 /usr/share/nginx/data/project 目录下的数据主要来自与共享 volume,这个 demo 是作为整体的一个部署。如果前端有版本的升级,提供新的镜像,重新做一次整体的部署即可。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants