Kubernetes中Nginx配置熱加載的全過(guò)程
前言
Nginx本身是支持熱更新的,通過(guò)nginx -s reload指令,實(shí)際通過(guò)向進(jìn)程發(fā)送HUB信號(hào)實(shí)現(xiàn)不停服重新加載配置,然而在Docker或者Kubernetes中,每次都需要進(jìn)容器執(zhí)行nginx -s reload指令,單docker容器還好說(shuō),可以在外面通過(guò)exec指定容器執(zhí)行該指令進(jìn)行熱加載,Kubernetes的話(huà),就比較難受了
今天介紹一下Kubernetes中Nginx熱加載配置的處理方法——reloader
reloader地址:https://github.com/stakater/Reloader
reloader主要就是用來(lái)監(jiān)測(cè)ConfigMap或Secret的變化,然后對(duì)相關(guān)DeploymentConfig的Deployment、DaemonSet執(zhí)行滾動(dòng)升級(jí)
reloader需要kubernetes1.9以上的版本才支持
使用方法
首先是安裝部署reloader
# 直接通過(guò)官方y(tǒng)aml文件部署 kubectl apply -f https://raw.githubusercontent.com/stakater/Reloader/master/deployments/kubernetes/reloader.yaml
默認(rèn)情況下reloader是部署在default命名空間,但是它是監(jiān)控所有命名空間的configmaps和secrets
當(dāng)然,如果不想監(jiān)控某個(gè)configmap或secret,可以通過(guò)--resources-to-ignore=configMaps/secrets來(lái)忽略某個(gè)資源
部署成功后,就可以直接使用了,我提前部署了nginx和configmap
這是目前的配置,看一下Nginx目前的配置
接著,我修改Nginx的Deployment,添加reloader,監(jiān)聽(tīng)nginx-config這個(gè)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應(yīng)用" # 主要是這行 "reloader.stakater.com/reload": "nginx-config" } }, "spec": { "replicas": 1, "selector": { "matchLabels": { "k8s-app": "nginx" } } ……
然后apply該Deployment,之后我們?nèi)ジ翪onfigMap,更新nginx配置文件
更新完成,去掉proxy_redirect,然后去看nginx容器是否執(zhí)行滾動(dòng)更新
可以看到,nginx執(zhí)行了滾動(dòng)更新,接著看下nginx配置文件是否更新
這樣很簡(jiǎn)單的通過(guò)reloader就可以實(shí)現(xiàn)Nginx的配置熱加載
除了這種方法,常見(jiàn)的方法還有使用sidecar,通過(guò)sidecar去做的話(huà),需要自己寫(xiě)監(jiān)聽(tīng)腳本,比較麻煩,但是有時(shí)候也相對(duì)靈活,這里也附一個(gè)sidecar的python腳本
#!/usr/bin/env python # -*- encoding: utf8 -*- """ 需求:nginx配置文件變化,自動(dòng)更新配置文件,類(lèi)似nginx -s reload 實(shí)現(xiàn): 1、用pyinotify實(shí)時(shí)監(jiān)控nginx配置文件變化 2、如果配置文件變化,給系統(tǒng)發(fā)送HUP來(lái)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)容就到這里
總結(jié)
到此這篇關(guān)于Kubernetes中Nginx配置熱加載的文章就介紹到這了,更多相關(guān)Kubernetes中Nginx配置熱加載內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Windows安裝nginx1.10.1反向代理訪(fǎng)問(wèn)IIS網(wǎng)站
這篇文章主要為大家詳細(xì)介紹了Windows安裝nginx1.10.1反向代理訪(fǎng)問(wèn)IIS網(wǎng)站的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11Windows下使用?Nginx?搭建?HTTP文件服務(wù)器?實(shí)現(xiàn)文件下載功能
Nginx?是一款輕量級(jí)的?HTTP?服務(wù)器,采用事件驅(qū)動(dòng)的異步非阻塞處理方式框架,這讓其具有極好的?IO?性能,時(shí)常用于服務(wù)端的反向代理和負(fù)載均衡,這篇文章主要介紹了Windows下使用?Nginx?搭建?HTTP文件服務(wù)器實(shí)現(xiàn)文件下載功能,需要的朋友可以參考下2023-03-03nginx FastCGI錯(cuò)誤Primary script unknown解決辦法
這篇文章主要介紹了nginx錯(cuò)誤Primary script unknown解決辦法,需要的朋友可以參考下2014-03-03Nginx配置server_name為域名后無(wú)法訪(fǎng)問(wèn)的問(wèn)題解決
在Nginx的配置文件中增加服務(wù)器,其server_name設(shè)置為域名時(shí),該網(wǎng)址不能正常訪(fǎng)問(wèn),所以本文給大家介紹了Nginx配置server_name為域名后無(wú)法訪(fǎng)問(wèn)的問(wèn)題解決,需要的朋友可以參考下2024-01-01centos系統(tǒng)下LNMP環(huán)境一鍵安裝
centos下的LNMP環(huán)境一鍵安裝實(shí)現(xiàn)方法,需要的朋友可以參考下。2010-06-06Tomcat請(qǐng)求處理在源碼中的輪轉(zhuǎn)解析
這篇文章主要為大家介紹了Tomcat請(qǐng)求處理在源碼中的輪轉(zhuǎn)解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08Nginx通過(guò)nginx-rtmp-module模塊搭建流媒體服務(wù)器實(shí)現(xiàn)直播
近日有客戶(hù)咨詢(xún)想用Nginx搭建流媒體服務(wù)器實(shí)現(xiàn)直播,方便他們打造自己的平臺(tái),經(jīng)過(guò)各種測(cè)試發(fā)現(xiàn)如下文章不錯(cuò),特分享給需要的朋友2023-10-10