0%

什么是Overlay网络, 用于解决什么问题 ?

Overlay网络通过在现有网络之上创建一个虚拟网络层, 解决不同主机的容器之间相互通信的问题
如果没有Overlay网络,实现跨主机的容器通信通常需要以下方法:

  • 端口映射
  • 使用宿主机网络模式

这些方法牺牲了容器网络隔离的优势, 并且可能导致端口冲突问题

以下搭建一个简易的Docker Swarm 集群(一主一从), 探究 Overlay 网络下不同节点上的容器间互相通信的原理

阅读全文 »

背景

早期,客户的On-premises网关设备(基于CentOS 7)采用增量升级方案进行固件更新。 这种方案存在两个主要问题:

  • 一旦升级过程中出现问题,客户只能重新安装系统,严重影响用户体验。
  • 部分客户未开启自动升级功能,为了支持所有客户的升级需求,升级包必须保存从初始版本到最新版本的所有增量文件。随着版本迭代,升级包变得越来越大,难以维护。

为了解决这些问题,需要为客户网关设备设计一种新的升级方案。

A/B系统升级简介

A/B分区升级机制允许设备在不同分区上安装和运行系统的不同版本,从而实现无缝更新。这种方法常用于移动设备、物联网设备以及其他需要高可用性和减少停机时间的场景中。例如,Android系统、Chrome OS及许多嵌入式和IoT设备都采用了A/B系统升级方法。其主要优点包括:

  • 无缝更新:可以在系统运行期间进行更新,唯一的宕机发生在设备重启到更新后分区时。
  • 故障恢复:如果升级失败,设备仍可工作在旧分区,并允许客户继续尝试升级。
阅读全文 »

背景

我们的客户有一些本地部署的网关设备(CentOS 7)需要做固件升级。 原有的单系统分区架构缺乏有效的回滚机制, 升级遇到故障后无法回滚, 导致服务中断, 用户体验差

目标

设计一种解决方案, 自动将客户的网关设备从单系统分区平滑升级到双系统,同时保证用户配置(IP, DNS, 登录口令)不丢失
整个升级过程对客户完全透明, 无需客户进行额外操作(比如添加磁盘, 创建新机器)

方案

设计如下方案:

方案 描述 优点 缺点
定制initramfs 通过定制initramfs进入紧急模式,预先加载升级包和配置文件到内存,再重建磁盘分区 用户无感知, 且备份了旧的配置 内存空间有限, 升级包+解压后系统文件需小于内存
安装ISO 下载并安装目标系统ISO 不需要单独出一个升级包 客户的配置很难同步, 升级后需要用户做一些手动配置
阅读全文 »

前言

我们在企业客户网络中部署了一些On-Premises的服务网关, 服务网关上部署了Squid代理软件, 为客户本地终端访问云服务提供正向代理
然而,对于使用较旧防火墙的客户来说,这些防火墙不支持基于FQDN(完全合格域名)的通配符匹配。这意味着当本地终端尝试访问云端资源时,用户必须逐一配置FQDN, 这种配置过程不仅繁琐,而且容易因为遗漏某些FQDN导致连接被防火墙阻止,造成网络中断,严重影响用户体验。
针对这个问题, 我们设计了一种基于Stunnel的加密通信方案, 绕过客户防火墙限制。 客户仅需配置Stunnel服务器的FQDN, 无需为每个目标服务器的FQDN进行单独设置, 从而简化了防火墙配置流程,提升了用户体验。

Stunnel是什么, 被设计用来解决什么问题

Stunnel是一款开源软件,其主要功能是为应用程序或服务提供TLS/SSL加密支持。 它的设计初衷是为了增强那些本身不支持加密功能的传统应用程序或服务的安全性
通过Stunnel, 可以在严格的防火墙规则下实现安全的加密通信,同时有效绕过可能存在的网络访问限制。

为什么需要Stunnel ?

直接通过墙内的Squid代理出去不行吗?

阅读全文 »

Microk8s Ingress是什么

Ingress是k8s的一种资源对象,用于管理外部对集群内服务的访问, 它通过提供一个统一的入口点,将外部流量路由到集群内部的不同服务。

Microk8s Ingress用于解决什么问题

k8s集群中服务默认只能在集群内访问。 如果需要从外部访问服务,通常需要使用NodePort或LoadBalancer类型服务,这两个服务都存在一些问题

  • NodePort会占用节点端口,可能导致端口冲突
  • LoadBalancer需要云提供商支持, 不适合本地环境
  • Ingress提供一种灵活的方式暴露服务,允许通过域名或路径规则将流量路由到不同的服务

Microk8s Ingress基本原理

  • Microk8s内置了一个Nginx的Ingress Controller, 负责监听k8s中的Ingress资源,当检测到Ingress资源更新时, 动态更新Nginx配置文件
  • 外部流量先到达Nginx, 再基于域名和URL将请求转发到Service, Service再将流量分发到Pod
阅读全文 »

前言

在我之前做的项目里,我们对Microk8s微服务的更新是通过自制tar包的方式做的, tar包存储了镜像和YAML文件。 每次升级时,我们需要先删除所有的YAML资源,然后重新创建新的资源。 这种方式存在以下问题:

  • 服务中断:由于需要先删除旧资源再创建新资源,这会导致短暂的服务中断,影响用户体验
  • 复杂的回滚逻辑:如果升级失败,回滚到之前的版本变得非常复杂,需要手动恢复旧的YAML文件,并且容易出错

了解到Helm可以有效解决以上问题, Helm是Kubernetes 的包管理工具,方便用户快速发现、 共享和使用Kubernetes构建的应用。 以下举例演示如何使用Helm实现安装、升级、回滚操作

阅读全文 »

前言

docker0是Docker默认网络的核心组件, 通过虚拟网桥和NAT技术, 实现了容器间的通信以及容器与外部网络的交互。然而, docker0网段是固定的(通常是172.17.0.0/16), 为了更灵活地管理容器网络,Docker支持创建自定义网桥,允许用户指定网段。
例如, 在我以前做的一个单板仿真项目里, 每个容器用来模拟一块板, 单板的IP需要设置为172.16.0.0/16, 和docker0网段不一致。 由于这个项目部署在每个开发的工作机上, 我们决定不直接修改docker0配置, 选择了创建自定义网桥这种更灵活的方式。

Docker网桥的工作机制

Docker在主机上创建一个虚拟网桥(docker0), 每当启动一个容器,Docker会自动创建一对虚拟网卡(veth pair), 其中一端放在容器内部作为它的网络接口, 另一端则连接到主机上的这个虚拟网桥。 通过这种方式,容器之间可以通过网桥直接通信,数据包在网桥内转发,不经过主机的物理网络接口。
如果容器访问的是外部网络, 容器发出的数据包会先通过虚拟网桥到达主机, 然后主机通过NAT将容器的私有IP替换为自己的公网IP,从而让数据包能够顺利发送到外部网络。

阅读全文 »

集群规划

8台Linux虚拟机, Rocky Linux 9.5 x86_64

  • 主节点(3个): 2CPU, 3G内存, 20G硬盘
  • 工作节点(2个): 2CPU, 3G内存, 20G硬盘
  • LB(2个): 1CPU, 2G内存, 10G硬盘

各个机器IP、主机名、角色如下

1
2
3
4
5
6
7
8
9
10
11
192.168.52.91 k8s-master1 主节点1
192.168.52.92 k8s-master2 主节点2
192.168.52.93 k8s-master3 主节点3

192.168.52.101 k8s-slave1 从节点1
192.168.52.102 k8s-slave2 从节点2
192.168.52.103 k8s-slave3 从节点3

192.168.52.80 k8s-lb1 HAProxy
192.168.52.81 k8s-lb2 HAProxy
192.168.52.88 www.petertest.com Virtual IP(VIP)

以下分步搭建kubernetes集群

  • 搭建一主一从集群
  • 添加负载均衡(HAProxy)
  • 搭建三主三从集群(三主三从两LB)
阅读全文 »

在 Docker 中,默认情况下容器无法直接与外部网络通信。 为了使外部网络能够访问容器内的服务,Docker 提供了端口映射功能,通过将宿主机的端口映射到容器内的端口,外部可以通过宿主机的IP和端口访问容器内的服务

以下通过动手演示, 安装一个Flask容器, 解释端口映射从外部访问容器的原理

安装一个Flask容器

文件结构

1
2
3
.
├── Dockerfile
└── app.py

Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
FROM rockylinux:9.3

RUN dnf update -y && \
dnf install -y python3 python3-pip && \
dnf clean all

WORKDIR /app

COPY app.py /app/app.py

RUN pip3 install --no-cache-dir flask

EXPOSE 5000

CMD ["python3", "app.py"]

app.py

1
2
3
4
5
6
7
8
9
10
from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello():
return "Hello"

if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)

构建镜像

1
docker build -t flask-app:1.0 .

启动容器, 进行端口映射

1
docker run -d -p 80:5000 flask-app:1.0

从外部访问 (192.168.52.203是我的虚拟机IP)

1
2
# curl 192.168.52.203
Hello
阅读全文 »

什么是 Docker 多阶段构建

Docker 多阶段构建是一种通过在单个 Dockerfile 中定义多个构建阶段的技术。 每个阶段可以使用不同的基础镜像和依赖项,允许开发人员在构建过程中分离应用程序的编译环境与运行环境。 最终生成的镜像只包含运行应用程序所需的文件,而无需携带编译工具链或其他不必要的依赖
通过多阶段构建,可以有效减少镜像体积,提升部署效率

实例: 多阶段构建压缩 Docker 镜像

下面通过一个简单的 Go 程序,分别用传统方式和多阶段构建两种方法演示如何构建 Docker 镜像,并观察多阶段构建对镜像大小的显著优化效果

准备工作

  • 安装 Docker
  • 编写一个简单的 Go 程序 hello.go
1
2
3
4
5
6
7
package main

import "fmt"

func main() {
fmt.Println("Hello, World!")
}
阅读全文 »