Docker 部署 Nginx 实现一个极简的 负载均衡

背景: Nginx是异步框架的网页服务器,其常用作反向代理(负载均衡器)。在一般的小项目中, 服务器不多, 如果不考虑使用服务注册与发现, 使用Nginx 可以容易实现负载均衡。 在特此写一个快速入门 Nginx 的技术贴, 使用 Docker 部署 Nginx, 实现一个极简的加权轮询负载均衡。

Docker 中 安装 Nginx

首先需要在docker 中拉取 nginx 镜像,命令行输入:

 

复制代码

docker pull nginx:latest

使用 latest 标签会拉取最新的稳定版镜像

拉取成功后使用下面这行命令应该可以看到 nginx:latest 的镜像

 

复制代码

docker images

随后根据镜像创建容器, 命令行输入

 

css

复制代码

docker run -d --name mynginx -p 30001:80 nginx:latest

这将在后台运行一个 名为 mynginx 的 nginx 容器, 容器外宿主机的 30001 端口映射到容器内部的 80端口。

安装成功后在浏览器输入: http://localhost:30001/,如果看到 Welcome to nginx 的字样说明Nginx 部署成功:

cdeb05e40d78d4a6531fa816c565281.png

写一个极简的 后端 handler

新建 一个 nginx_demo 目录 命令行输入

 

go

复制代码

go mod init nginx_demo go mod tidy

然后 在 nginx_demo 目录下新建一个 server.go 文件:

 

go

复制代码

package main import ( "fmt" "net/http" ) func HelloHandler(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello From XX.XX.XX.XX.")) # 替换成docker 容器的 IP地址 } func main() { http.HandleFunc("/hello", HelloHandler) errChan := make(chan error) go func() { errChan <- http.ListenAndServe(":20001", nil) }() err := <-errChan if err != nil { fmt.Println("Hello server stop running.") } }

特别注意的是第九行, 需要替换成docker 容器的IP地址, 因为等一会我们需要将这个 go 工程部署到不同的机器上去(docker 容器中), 为了展现效果, 这里直接把IP地址打印出来。

部署 Nginx 和 Go 工程到 docker 中

部署 go 工程

首先我把 这个 go 工程部署到两给不同的 go 容器中去

如何 docker 中搭建 go 开发环境可以参考我的另一篇 文章: 保姆级从0到1讲解go远程开发环境搭建(从Docker安装到使用Goland远程部署和调试)

部署的方式如下表所示:

IP端口映射 (宿主机 -> docker 容器)http 监听端口
127.17.0.43333 -> 2220001
127.17.0.34444 -> 2220001

想要查看 容器 IP 可以输入下面这条命令

 

scss

复制代码

docker inspect 容器ID(或者容器名)

查看 IPAddress 字段就是 容器 IP

部署 Nginx
更改配置文件

刚才上面已经启动了 Nginx , 我们需要改的只是配置文件

使用 docker cp 命令将 容器内默认的配置文件 复制出来

 

bash

复制代码

docker cp mynginx:/etc/nginx/nginx.conf nginx.conf

复制出来的配置文件大概长这样:

 

conf

复制代码

user nginx; worker_processes auto; error_log /var/log/nginx/error.log notice; 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; #tcp_nopush on; keepalive_timeout 65; #gzip on; include /etc/nginx/conf.d/*.conf; }

我们修改后长这样:

 

ini

复制代码

user nginx; worker_processes auto; error_log /var/log/nginx/error.log notice; 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; #tcp_nopush on; keepalive_timeout 65; #gzip on; (必须把这下面行注释掉, 否则会去拉取默认的配置, 导致这个文件的修改不生效) #include /etc/nginx/conf.d/*.conf; upstream RoundWeightLoadBalancer { # 加权 轮询 负载均衡 server 172.17.0.4:20001 weight=1; server 172.17.0.3:20001 weight=2; } server { listen 80; server_name localhost; location / { proxy_pass http://RoundWeightLoadBalancer ; } } }

主要修改了下面几个地方:

1. 注释了 include /etc/nginx/conf.d/*.conf;

这是一个大坑, 如果不注释, 则会去拉取默认的配置, 导致这个文件的修改不生效。我曾就是在这里被坑了一个星期,最后才发现原来是这里出错。

2. 新建了 upStream 标签

upstream 标签后面跟 负载均衡器 的名字, 可以自定义。标签内加 server + IP + 端口。我这里在后面还加了 weight 表示权重。我这里演示的是最简单的轮询加权, 也就是请求一个个按顺序被分配到不同的机器上, 其中 172.17.0.4 机器会被访问到1次, 172.17.0.3 会被访问到两次(因为权重比是1比2). 当然还有别的负载均衡方式, 可以访问 Nginx 的官方文档, 我这里主要关注与快速上手Nginx, 所以就选了给最简单最容易看出效果的 加权轮询策略。

3. 新增了 server 标签

server 标签 主要定义了三件事

  • 监听端口
  • server name,因为是部署到本地, 直接使用localhost
  • location 定义了转发规则, 比如 / 表示将所有请求直接进行转发, 转发到 upstream 标签定义的 RoundWeightLoadBalancer 负载均衡规则

有个很坑的地方: 如果 后端的handler 不位于 docker 容器内, 而是在宿主机, 这就涉及到了了 Nginx 容器如何往外通信的问题. 可以这么写 proxy_pass:

 

bash

复制代码

proxy_pass http://host.docker.internal:20001/hellou;

使用 host.docker.internal将Nginx的请求转发回宿主机。

重启 Nginx

首先将保存好的 配置文件 复制到 docker 容器中

 

bash

复制代码

docker cp nginx.conf mynginx:/etc/nginx/nginx.conf

随后重启 Nginx

 

复制代码

nginx -s reload

运行 起来

在 两个 go 工程的目录下(容器中) 命令行输入

 

go

复制代码

go mod tidy go run server.go

宿主机 中打开 Postman 或者 浏览器输入 :http://localhost:30001/hello

image.png

1671370480036.png

来自于 Hello From 127.17.0.3 和 Hello From 127.17.0.4 的响应会交替出现, 其中Hello From 127.17.0.3的 响应会连续出现两次, Hello From 127.17.0.4的响应只会出现一次, 这和 1比2 的轮询权重是相符合的。

回顾一下转发过程

宿主机的 30001 端口的请求打到 Nginx 容器的 80端口, Nginx 监听 80端口, 将 / 对应的所有请求转发到 127.17.0.3:20001 和 127.17.0.4:20001, 转发比例为1比2.

  下面是配套资料,对于做【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!

软件测试面试小程序
被百万人刷爆的软件测试题库!!!谁用谁知道!!!全网最全面试刷题小程序,手机就可以刷题,地铁上公交上,卷起来!

涵盖以下这些面试题板块:

1、软件测试基础理论 ,2、web,app,接口功能测试 ,3、网络 ,4、数据库 ,5、linux 6、web,app,接口自动化 ,7、性能测试 ,8、编程基础,9、hr面试题 10、开放性测试题,11、安全测试,12、计算机基础

​编辑资料获取方式 :xiaobei_upup,添加时备注“csdn alex”

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/626059.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

obsidian 外观设置解毒

前言 一入obsidian深似海&#xff0c;外观设置也是五花八门&#xff0c;仿佛回到读书时期折腾桌面一样。 我对比了AnuPpuccin、minimal和其他的一些外观主题&#xff0c;设置都太复杂了&#xff0c;尤其是需要调整CSS文件&#xff0c;最后发现一款&#xff0c;非常好用&#…

OpenHarmony 3.1 Release实战开发 + Linux 原厂内核Launcher起不来问题分析报告

1、关键字 Launcher 无法启动&#xff1b;原厂内核&#xff1b;Access Token ID&#xff1b; 2、问题描述 芯片&#xff1a;rk3566&#xff1b;rk3399 内核版本&#xff1a;Linux 4.19&#xff0c;是 RK 芯片原厂发布的 rk356x 4.19 稳定版内核 OH 版本&#xff1a;OpenHa…

接口、会话控制

文章目录 接口介绍RESTful APIjson-server接口测试工具apipost公共参数和文档功能 会话控制cookie介绍和使用运行流程浏览器中操作Cookieexpress中cookie操作 Sessionsession运行流程&#xff1a;session中间件配置session 和 cookie 的区别CSRF跨站请求伪造 tokenJWT介绍与演示…

JavaScript的综合案例

案例要求&#xff1a; 实现一个表单验证 1.当输入框失去焦点时&#xff0c;验证输入的内容是否符合要求 2.当点击注册按钮时&#xff0c;判断所有输入框的内容是否都符合要求&#xff0c;如果不符合要求阻止表单提交 简单的页面实现 <!DOCTYPE html> <html lang&…

【IDE】com.intellij.debugger.engine.evaluation.EvaluateException

目录标题 报错重现代码分析解决方式 报错重现 Error during generated code invocation com.intellij.debugger.engine.evaluation.EvaluateException: Method threw java.lang.NullPointerException exception.代码分析 //ls来自上下文 ls.stream().map(m->m.getRewardTy…

tarjan学习

1.割点&#xff08;必须经过&#xff09;&#xff1a;当时&#xff0c;y是一个割点&#xff0c;x是y的一个子节点&#xff0c;当没有点x时&#xff0c;y无法访问其他点 2.割边&#xff08;必须经过&#xff09;&#xff1a;当时&#xff0c;y不经过这条边无法到达x&#xff0c…

深入了解 npm:Node.js 包管理工具详解

文章目录 一、npm 基本概念1.1 什么是 npm&#xff1f;1.2 package.json 文件 二、npm 常用命令2.1 初始化项目2.2 安装依赖2.2.1 安装单个包2.2.2 全局安装包2.2.3 安装开发依赖 2.3 移除依赖2.4 更新依赖2.5 查看已安装的包2.6 发布包 三、npm 高级用法3.1 使用 npm scripts3…

嵌入式学习-M4的基本定时器

基本介绍 框图分析 时钟选择 计数器结构 开启重装载值寄存器的影子寄存器的工作时序图 未开启重装载值寄存器的影子寄存器的工作时序图 更新事件以及中断 相关寄存器 相关库函数

RK3566(泰山派):GP7101背光驱动

RK3566&#xff08;泰山派&#xff09;&#xff1a;GP7101背光驱动 文章目录 RK3566&#xff08;泰山派&#xff09;&#xff1a;GP7101背光驱动GP7101背光驱动电路配置i2c1设备树创建驱动编写Makefilegp7101_bl.c驱动触摸I2C驱动框架。驱动中的结构体probe函数devm_backlight_…

探索数据结构:堆的具体实现与应用

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;数据结构与算法 贝蒂的主页&#xff1a;Betty’s blog 1. 堆的概念 堆(Heap)是计算机科学中一类特殊的数据结构。堆通常是一个…

SpringBoot项目的项目部署全过程

一、前端 安装nginx 1.将提前准备好的nginx的安装包上传到Linux中/opt目录下(我用的是Xftp) 2.解压 2.1:在xshell中解压该文件: tar -zxvf nginx-1.20.1.tar.gz 2.2:进入解压后的目录 cd nginx-1.20.1/ 2.3:安装需要的依赖 yum -y install zlib zlib-devel openssl openssl-de…

Keil编程不同驱动文件引用同一个常量的处理方法

基础不牢&#xff0c;地动山摇&#xff0c;最近单片机编程又遇到一个基础问题。 我在头文件中定义了一个常量同时给两个驱动文件使用&#xff0c;封装的时候编译没问题&#xff0c;但是在main函数中引用驱动函数的时候就出现了重定义的问题&#xff0c;如下如所示。 解决方法很…

8.基于鱼鹰优化算法(OOA)优化VMD参数(OOA-VMD)

代码原理 鱼鹰优化算法&#xff08;Osprey Optimization Algorithm, OOA&#xff09;是一种基于仿生学原理的启发式优化算法&#xff0c;它模拟了鱼鹰觅食的行为&#xff0c;通过调整搜索空间中的个体位置来优化目标函数。 鱼鹰优化算法可参考&#xff1a;鱼鹰优化算法(Ospre…

Network Compression

听课&#xff08;李宏毅老师的&#xff09;笔记&#xff0c;方便梳理框架&#xff0c;以作复习之用。本节课主要讲了Network Compression&#xff0c;包括为什么要压缩&#xff0c;压缩的主要手段&#xff08;pruning,knowledge distillation,parameter quantization,architect…

C# 下载安装,使用OfficeOpenXml

下载安装OfficeOpenXml模块 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Reflection.Emit; using System.Text; using System.Text.RegularEx…

【大道至简】官方兼容到android13+的获取系统屏幕高度, statusbar,navBar

android在屏幕高度和app高度&#xff0c;statusbar, navigationbar的高度处理上&#xff0c;迭代了好多版本。 android11&#xff0c; android12都有新的api和过时的api标记。 涉及的api类似如下&#xff1a; windowManager&#xff0c;defaultDisplay, Context.display, Deco…

uniapp开发安卓app使用文字转语音技术

在 UniApp 开发安卓应用时&#xff0c;要实现文字转语音&#xff08;Text-to-Speech, TTS&#xff09;技术&#xff0c;你可以利用 UniApp 的跨平台能力结合原生模块或第三方服务来实现。以下是一些建议的步骤和方法&#xff1a; 1. 使用 UniApp 原生模块&#xff08;如果支持…

怎么得到所有大写字母/小写字母组成的字符串

有时候&#xff0c;可能需要获取a~z、A~Z组成的26个字母的字符串&#xff0c;这篇文章介绍一种简单的方法。 只需要几句简单到不能再简单的代码&#xff01;你不会还在傻傻地一个个字母敲吧~ /*** author heyunlin* version 1.0*/ public class Example {/*** 小写字母*/priv…

通信指挥类装备(多链路聚合设备)-应急通信指挥解决方案

现场通信指挥系统是一种功能全面的便携式音视频融合指挥通信平台&#xff0c;可实现现场应急救援指挥、多种通信手段融合、现场通信组网等功能&#xff0c;是现场指挥系统的延伸。 多链路聚合设备&#xff0c;是一款通信指挥类装备&#xff0c;具有 4G/5G&#xff0c;专网&…

ResNeXt

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊# 前言 前言 前面已经学习了resnet家族已经inception卷积网络&#xff0c;还简单了解了SE注意力机制&#xff0c;今天学习resnet和inception的组合ResNeXt。 …