当前位置: 首页 > news >正文

从零开始搞个简易分布式部署环境

从零开始,意味着连个服务器都没有,所以第一步,随便上哪个顺眼的云厂家去租个便宜大碗的服务器(不要window系统的就行),说大碗也不太对,主要是这碗能在手里用得久,这个就自己扒拉去了。

简易,意味着这个分布式环境都是在这个服务器里用容器搭出来的自娱自乐的环境,跟实际正经的由不同主机组成的分布式环境依然有相当大的区别,最大的区别就是:省钱!

至于为什么不在自己电脑上搞虚拟机双系统啥的去模拟,我只能说我自己的破烂电脑背上这么多负担还真不一定比租个云服务器便宜方便,如果你电脑配置很牛逼,那当我没说。

那么,就开始从零开始了。

这个分布式环境都需要什么?

首先,要有一个应用,如果是搞Java开发的,大概率就会是个springboot应用,那么随便写一个返回 hello world 的 controller 再写好 Application 最后打包成一个 jar,这就是第一个需要的东西。

这一步是在自己本机完成的,也是本文中本机唯一做的事,接下来的其他步骤就全是在租下来的云服务器上的操作了。

云服务器环境准备

首先,更新服务器的 apt 或者 yum 或其他什么都好的安装工具,因为不更新的话有很大概率你啥都安装不了(苦涩)。

sudo apt update && sudo apt upgrade
# 或者
sudo yum update
# 下面各种乱七八糟的安装就用 apt 的写了,yum 的也一样,就这三个字母的差别。

然后,下载 docker-ce ,注意这个后缀,带此后缀的是 docker 的社区版,免费开源,更新频繁(每月发布新版本),适合个人开发者和小团队使用。

apt install -y docker-ce docker-ce-cli containerd.io

在这个环节,大概率会遇到:

  1. yum 版本太低,docker-ce没法下载,忽悠你下载 docker

解: yum install -y yum-utils 把Red Hat Enterprise Linux(RHEL)或 CentOS 的系统上可能缺失(因为系统已经被改成了阿里云的系统)的 yum-utils 下载回来,这是个包管理工具。

  1. 没配置下载仓库

解: yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 记得用国内镜像,docker 官方镜像容易超时连接失败。

  1. 下载完docker命令不生效

解:systemctl enable docker检查 docker 是否可用,systemctl start docker启动docker。

  1. 其他

解:未完待续……

大部分问题善用搜索引擎或描述给人机师傅基本也能得到解决。这里就只记录我自己遇到过的。

JDK下载与容器创建

在 docker 安装完后,就开始下载 jdk 了。我准备测试三个jdk环境:8、11、17。

# 下载解压jdk8,下面的 11 和 17 也是相同的命令
wget -qO- https://download.java.net/openjdk/jdk8u42/ri/openjdk-8u42-b03-linux-x64-14_jul_2022.tar.gz | tar -xz
wget -qO- https://download.java.net/openjdk/jdk11/ri/openjdk-11+28_linux-x64_bin.tar.gz | tar -xz
wget -qO- https://download.java.net/openjdk/jdk17/ri/openjdk-17+35_linux-x64_bin.tar.gz | tar -xz

这三个jdk需要放在单独的文件夹下,因为等会儿创建容器的时候要把这个路径映射到容器里,方便日后容器内测试不同版本jdk。这里也先提前写一个切换环境变量的脚本放在同级文件夹下,这样容器内就可以直接操作使用。

#!/bin/bash# 检查是否传入参数(JDK版本号)
if [ $# -eq 0 ]; thenecho "错误:请指定JDK版本号(如8、11、17等)"echo "用法:./set_java.sh <版本号>"exit 1
fi# 设置JAVA_HOME和PATH
export JAVA_HOME="/opt/java/jdk$1"  # 使用第一个参数$1替换版本号
export PATH="$JAVA_HOME/bin:$PATH"# 验证Java版本
java -version

经测试,容器内使用这个脚本需要用source而不是bash执行才能顺利地修改容器内的 Java 环境,有些教程会让写成系统命令,配置成类似 systemctl 那样的,但我这边用了下不太行得通。而用bash执行会创建一个隔离的shell环境,导致切换环境变量的操作只在这次执行中生效,当执行完毕想再用 java -version 确认版本会发现依然是旧的jdk。

脚本准备好,接下来就是创建容器了。

# 容器创建
docker run -itd --name apps \# 这里依次映射了三个版本的jdk路径-v /home/workspace/java/jdk8:/opt/java/jdk8 \-v /home/workspace/java/jdk11:/opt/java/jdk11 \-v /home/workspace/java/jdk17:/opt/java/jdk17 \# 也可以直接把上层文件夹映射到容器里-v /home/workspace/java:/opt/java \# 这里是要部署的应用的映射地址-v /home/workspace/app1/app1:/data/app1/ \# 预先配置容器创建时的jdk版本-e JAVA_HOME=/opt/java/jdk8 \-e PATH=/opt/java/jdk/bin:$PATH \# 映射端口取8085,也可以用常用的80和8080-p 8085:8085 \# 使用ubuntu20.04镜像ubuntu:20.04 /bin/bash

MySQL容器创建

MySQL同样弄了两个版本,一个是最常用的5.7,一个是MySQL8,也是纯测试用。

由于我租的服务器资源有限,这里显式指定了容器的内存(512 M)和可用的 cpu (0.5个核的算力),防止日后占用过多资源。

# 5.7
docker run -d --name mysql57 \-e MYSQL_ROOT_PASSWORD=root \# 将容器的3306映射到宿主机的3306,方便以后用工具连接查看-p 3306:3306 \-v /home/workspace/mysql/mysql57:/var/lib/mysql \--memory="512m" \--cpus="0.5" \mysql:5.7# 8.0
docker run -d --name mysql80 \-e MYSQL_ROOT_PASSWORD=root \# 将容器的3306映射到宿主机的3307,方便以后用工具连接查看-p 3307:3306 \-v /home/workspace/mysql/mysql80:/var/lib/mysql \--memory="512m" \--cpus="0.5" \mysql:8.0

--memory="512m" 是容器内所有进程(包括MySQL及其子进程)的总内存上限,当容器的内存使用量超过 512 MB 时,Docker 会触发内存不足终止机制(OOM Killer),强制终止容器进程(显示为容器崩溃或退出)。

这个限制仅包括物理内存,不包括交换分区(Swap)。如需限制交换分区,需额外配置 --memory-swap

交换分区(Swap Space)  是什么?

是操作系统(如 Linux)中一种特殊的磁盘空间,用于在物理内存(RAM)不足时,临时存储被换出的内存页(即不活跃的进程数据)。它的核心作用是 扩展虚拟内存 ,防止系统因内存耗尽而崩溃。

docker 的 memory-swap 需要结合宿主机的 swap 配置启用,也需要这个容器已经配置了--memory。相关配置在官方文档中可以找到说明:https://docs.docker.com/engine/containers/resource_constraints/#–memory-swap-details

MySQL 8.0 默认配置可能默认需要较多内存(如 innodb_buffer_pool_size 默认 128MB),建议根据业务调整 MySQL 配置以避免内存不足。

可通过 docker stats <容器名> 实时监控容器的内存和 CPU 使用情况。

Redis 和 RabbitMQ 容器创建

如果你的应用没用到这两个,没关系,早晚会用到的(

# Redis 创建,同样限制了最大可用内存和 CPU 计算资源
docker run -d --name redis \-p 6379:6379 \--memory 100m \--cpus 0.1 \redis:alpine# RabbitMQ 创建,同样限制了最大可用内存和 CPU 计算资源
docker run -d --name rabbitmq \-p 15672:15672 \--memory 200m \--cpus 0.2 \rabbitmq:management-alpine

nginx 配置

nginx 基本就是配置文件的编写。

docker run -d --name nginx-proxy \--network my-network \-p 80:80 \-p 443:443 \-v /home/workspace/nginx/:/home/workspace/nginx \-v /home/workspace/nginx/nginx.conf:/etc/nginx/nginx.conf \nginx

--network 是 docker 网络的配置,这点后面会说,并且前面几个容器也需要补充配置,好在不需要删除容器,有单独将容器添加到网络里的命令。

nginx 绑定的配置文件里需要下面这些东西。

// nginx 的配置文件其实不是json格式,但代码块用json有比较方便的颜色区分……
events {worker_connections 1024;
}http {server {listen 80;# 监听端口server_name 云服务器IP;// 下面这个 // 不是注释的意思,别删错了return 301 https://$host$request_uri;}server{listen 443 ssl;server_name 云服务器IP;//这两个是ssl证书地址,有专门用于测试的获取渠道//正规的一般需要付费购买,且前提是有域名ssl_certificate /home/workspace/nginx/ssl/cert.pem;ssl_certificate_key /home/workspace/nginx/ssl/key.pem;ssl_protocols TLSv1.2 TLSv1.3;ssl_ciphers HIGH:!aNULL:!MD5;location / {proxy_pass http://apps(部署应用的容器名):8085;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;}}
}

本地创建ssl测试证书的命令是:
openssl req -x509 -newkey rsa:4096 -nodes -out cert.pem -keyout key.pem -days 365,生成的两个文件放到前面配置的 ssl_certificate 和 ssl_certificate_key 的路径下就行。

上面的 nginx 配置实际上只是转发云服务器的80端口到指定的有且只有一个的应用容器上,但在分布式情况下,应用容器不会只有一个,因此你需要的是下面字更多的版本。

events {worker_connections 1024;
}http {upstream app_servers{server apps1:8085;server apps2:8085;server apps3:8085;}server {listen 80;server_name 云服务器IP;// 下面这个 // 不是注释的意思,别删错了return 301 https://$host$request_uri;}server{listen 443 ssl;server_name 云服务器IP;ssl_certificate /home/workspace/nginx/ssl/cert.pem;ssl_certificate_key /home/workspace/nginx/ssl/key.pem;ssl_protocols TLSv1.2 TLSv1.3;ssl_ciphers HIGH:!aNULL:!MD5;location / {// 下面这个 // 不是注释的意思,别删错了proxy_pass http://app_servers;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;}}
}

nginx 的配置文件修改后要生效只需要简单地重启容器docker start nginx-proxy

到这里一个极简的分布式环境差不多就搞好了,可以开始玩了(。

相关文章:

  • 【大模型原理与技术-毛玉仁】第二章 大语言模型架构
  • LangChain快速入门:使用LangChain构建高效的并行语言处理链
  • 切换到旧提交,同时保证当前修改不丢失
  • WMS系统选型与实施避坑手册
  • android系统framework的几个新面试题目(涉及binder,input,SurfaceFlinger带答案)
  • 基于DFT码本的波束方向图生成MATLAB实现
  • Next.js 15 与 Apollo Client 的现代集成及性能优化
  • 低功耗双目云台监控设备采用国标控制装置
  • 【Java工程师面试全攻略】Day3:Java并发编程面试精要
  • 编译Ambari 3.0.0全攻略
  • Rust 的Hello World
  • 程序员出海手册
  • Git:现代软件开发的基石——原理、实践与行业智慧·优雅草卓伊凡
  • 实验设计与分析(第6版,Montgomery)第4章随机化区组,拉丁方, 及有关设计4.5节思考题4.18~4.19 R语言解题
  • python学习day31
  • 如何发布npm包?
  • 2024 CKA模拟系统制作 | Step-By-Step | 11、题目搭建-查看可用节点数量
  • 20250528-C#知识:结构体
  • Spring AI系列之使用 Mistral AI API 实现函数调用
  • 使用LSTM进行时间序列分析
  • 如何在已建设好的网站做修改/百度推广排名怎么做的
  • 免费网页设计模板网站/网络营销促销方案
  • 陇南建设网站/百度seo收录软件
  • 沈阳网站设计制作公司/app拉新推广一手接单平台
  • 网站开发怎么拉客户/如何优化百度seo排名
  • 外贸网站源码是什么/互联网产品推广