溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Kubernetes中Nginx配置熱加載的過程是怎樣的

發(fā)布時間:2022-01-19 13:28:43 來源:億速云 閱讀:129 作者:柒染 欄目:開發(fā)技術(shù)

Kubernetes中Nginx配置熱加載的過程是怎樣的,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。

前言

Nginx本身是支持熱更新的,通過nginx -s reload指令,實際通過向進程發(fā)送HUB信號實現(xiàn)不停服重新加載配置,然而在Docker或者Kubernetes中,每次都需要進容器執(zhí)行nginx -s reload指令,單docker容器還好說,可以在外面通過exec指定容器執(zhí)行該指令進行熱加載,Kubernetes的話,就比較難受了

今天介紹一下Kubernetes中Nginx熱加載配置的處理方法——reloader

reloader地址:https://github.com/stakater/Reloader

reloader主要就是用來監(jiān)測ConfigMap或Secret的變化,然后對相關(guān)DeploymentConfig的Deployment、DaemonSet執(zhí)行滾動升級

reloader需要kubernetes1.9以上的版本才支持

使用方法

首先是安裝部署reloader

# 直接通過官方y(tǒng)aml文件部署
kubectl apply -f https://raw.githubusercontent.com/stakater/Reloader/master/deployments/kubernetes/reloader.yaml

默認情況下reloader是部署在default命名空間,但是它是監(jiān)控所有命名空間的configmaps和secrets

當然,如果不想監(jiān)控某個configmap或secret,可以通過--resources-to-ignore=configMaps/secrets來忽略某個資源

Kubernetes中Nginx配置熱加載的過程是怎樣的

部署成功后,就可以直接使用了,我提前部署了nginx和configmap

Kubernetes中Nginx配置熱加載的過程是怎樣的

這是目前的配置,看一下Nginx目前的配置

Kubernetes中Nginx配置熱加載的過程是怎樣的

接著,我修改Nginx的Deployment,添加reloader,監(jiān)聽nginx-config這個ConfigMap,執(zhí)行reload

{
  "kind": "Deployment",
  "apiVersion": "extensions/v1beta1",
  "metadata": {
    "name": "nginx",
    "namespace": "default",
    "selfLink": "/apis/extensions/v1beta1/namespaces/default/deployments/nginx",
    "uid": "7eee5fa8-7514-11ec-a916-0210d5e9ca3b",
    "resourceVersion": "286141",
    "generation": 10,
    "creationTimestamp": "2022-01-14T08:32:23Z",
    "labels": {
      "k8s-app": "nginx"
    },
    "annotations": {
      "deployment.kubernetes.io/revision": "9",
      "description": "nginx應用"
      # 主要是這行
      "reloader.stakater.com/reload": "nginx-config"
    }
  },
  "spec": {
    "replicas": 1,
    "selector": {
      "matchLabels": {
        "k8s-app": "nginx"
      }
    }
    ……

然后apply該Deployment,之后我們?nèi)ジ翪onfigMap,更新nginx配置文件

Kubernetes中Nginx配置熱加載的過程是怎樣的

更新完成,去掉proxy_redirect,然后去看nginx容器是否執(zhí)行滾動更新

Kubernetes中Nginx配置熱加載的過程是怎樣的

可以看到,nginx執(zhí)行了滾動更新,接著看下nginx配置文件是否更新

Kubernetes中Nginx配置熱加載的過程是怎樣的

這樣很簡單的通過reloader就可以實現(xiàn)Nginx的配置熱加載

除了這種方法,常見的方法還有使用sidecar,通過sidecar去做的話,需要自己寫監(jiān)聽腳本,比較麻煩,但是有時候也相對靈活,這里也附一個sidecar的python腳本

#!/usr/bin/env python
# -*- encoding: utf8 -*-
"""
需求:nginx配置文件變化,自動更新配置文件,類似nginx -s reload
實現(xiàn):
    1、用pyinotify實時監(jiān)控nginx配置文件變化
    2、如果配置文件變化,給系統(tǒng)發(fā)送HUP來reload nginx
"""
import os
import re
import pyinotify
import logging
from threading import Timer

# Param
LOG_PATH = "/root/python/log"
CONF_PATHS = [
  "/etc/nginx",
]
DELAY = 5
SUDO = False
RELOAD_COMMAND = "nginx -s reload"
if SUDO:
  RELOAD_COMMAND = "sudo " + RELOAD_COMMAND

# Log
logger = logging.getLogger(__name__)
logger.setLevel(level = logging.INFO)
log_handler = logging.FileHandler(LOG_PATH)
log_handler.setLevel(logging.INFO)
log_formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
log_handler.setFormatter(log_formatter)
logger.addHandler(log_handler)

# Reloader
def reload_nginx():
  os.system(RELOAD_COMMAND)
  logger.info("nginx is reloaded")

t = Timer(DELAY, reload_nginx)

def trigger_reload_nginx(pathname, action):
  logger.info("nginx monitor is triggered because %s is %s" % (pathname, action))
  global t
  if t.is_alive():
    t.cancel()
    t = Timer(DELAY, reload_nginx)
    t.start()
  else:
    t = Timer(DELAY, reload_nginx)
    t.start()

events = pyinotify.IN_MODIFY | pyinotify.IN_CREATE | pyinotify.IN_DELETE

watcher = pyinotify.WatchManager()
watcher.add_watch(CONF_PATHS, events, rec=True, auto_add=True)

class EventHandler(pyinotify.ProcessEvent):
  def process_default(self, event):
    if event.name.endswith(".conf"):
      if event.mask == pyinotify.IN_CREATE:
        action = "created"
      if event.mask == pyinotify.IN_MODIFY:
        action = "modified"
      if event.mask == pyinotify.IN_DELETE:
        action = "deleted"
      trigger_reload_nginx(event.pathname, action)

handler = EventHandler()
notifier = pyinotify.Notifier(watcher, handler)

# Start
logger.info("Start Monitoring")
notifier.loop()

如果喜歡用go的,這里也提供go腳本

package main

import (
    "log"
    "os"
    "path/filepath"
    "syscall"

    "github.com/fsnotify/fsnotify"
    proc "github.com/shirou/gopsutil/process"
)

const (
    nginxProcessName = "nginx"
    defaultNginxConfPath = "/etc/nginx"
    watchPathEnvVarName = "WATCH_NGINX_CONF_PATH"
)

var stderrLogger = log.New(os.Stderr, "error: ", log.Lshortfile)
var stdoutLogger = log.New(os.Stdout, "", log.Lshortfile)

func getMasterNginxPid() (int, error) {
    processes, processesErr := proc.Processes()
    if processesErr != nil {
        return 0, processesErr
    }

    nginxProcesses := map[int32]int32{}

    for _, process := range processes {
        processName, processNameErr := process.Name()
        if processNameErr != nil {
            return 0, processNameErr
        }

        if processName == nginxProcessName {
            ppid, ppidErr := process.Ppid()

            if ppidErr != nil {
                return 0, ppidErr
            }

            nginxProcesses[process.Pid] = ppid
        }
    }

    var masterNginxPid int32

    for pid, ppid := range nginxProcesses {
        if ppid == 0 {
            masterNginxPid = pid

            break
        }
    }

    stdoutLogger.Println("found master nginx pid:", masterNginxPid)

    return int(masterNginxPid), nil
}

func signalNginxReload(pid int) error {
    stdoutLogger.Printf("signaling master nginx process (pid: %d) -> SIGHUP\n", pid)
    nginxProcess, nginxProcessErr := os.FindProcess(pid)

    if nginxProcessErr != nil {
        return nginxProcessErr
    }

    return nginxProcess.Signal(syscall.SIGHUP)
}

func main() {
    watcher, watcherErr := fsnotify.NewWatcher()
    if watcherErr != nil {
        stderrLogger.Fatal(watcherErr)
    }
    defer watcher.Close()

    done := make(chan bool)
    go func() {
        for {
            select {
            case event, ok := <-watcher.Events:
                if !ok {
                    return
                }

                if event.Op&fsnotify.Create == fsnotify.Create {
                    if filepath.Base(event.Name) == "..data" {
                        stdoutLogger.Println("config map updated")

                        nginxPid, nginxPidErr := getMasterNginxPid()
                        if nginxPidErr != nil {
                            stderrLogger.Printf("getting master nginx pid failed: %s", nginxPidErr.Error())

                            continue
                        }

                        if err := signalNginxReload(nginxPid); err != nil {
                            stderrLogger.Printf("signaling master nginx process failed: %s", err)
                        }
                    }
                }
            case err, ok := <-watcher.Errors:
                if !ok {
                    return
                }
                stderrLogger.Printf("received watcher.Error: %s", err)
            }
        }
    }()

    pathToWatch, ok := os.LookupEnv(watchPathEnvVarName)
    if !ok {
        pathToWatch = defaultNginxConfPath
    }

    stdoutLogger.Printf("adding path: `%s` to watch\n", pathToWatch)

    if err := watcher.Add(pathToWatch); err != nil {
        stderrLogger.Fatal(err)
    }
    <-done
}

ok,今天的內(nèi)容就到這里

看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進一步的了解或閱讀更多相關(guān)文章,請關(guān)注億速云行業(yè)資訊頻道,感謝您對億速云的支持。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI