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

K8S中构建双架构镜像-从零到成功

背景介绍

公司一个客户的项目使用的全信创的环境,服务器采用arm64的机器,而我们的应用全部是amd64的,于是需要对现在公司流水线进行arm64版本的同步镜像生成。本文介绍从最开始到最终生成双架构的全部过程,以及其中使用的相关配置文件。如果大家有需要请仔细阅读。

环境介绍

K8S 版本:

Client Version: v1.32.3
Kustomize Version: v5.5.0
Server Version: v1.32.3

CICD平台: KubeSphere 4.1.3 (这个平台无关紧要,只有理解思路就可以了)

镜像仓库: Harbor 2.13.0 ,使用私有的域名和自签的证书,这个场景应该是大多数自建harbor的情况,我在自签证书上踩了很多坑,如果有条件的使用授信的CA的证书

思路介绍

  • 运用buildkit 工具进行多架构构建
  • 流水线步骤: 克隆代码 -> 编译代码 -> 构建多架构镜像并推送, 在Dockerfile中判定容器的架构并拷贝不同的应用制品,如果是Java和VUEJS不需要做这个判定。

前置条件

  • 在harbor中已经具备同一个镜像tag,不同的架构的镜像。其中包含: binfmt,buildkit,openeuler(应用运行的基础镜像)

步骤

一 、解决buildkit拉取和上传镜像对证书的不信任

  • 获取自建harbor的ca证书文件
echo -n | openssl s_client -showcerts -connect harbor.easzlab.io.local:443 |   sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > harbor-ca.crt
  • 将harbor 的ca文件添加到buildkit的镜像中,对下面的命令如果有疑虑请参考我的另外一个文章【Docker多架构镜像构建踩坑记】,这个命令会同时构建出来多架构的基础镜像并推送到仓库中
docker buildx build --platform=linux/amd64,linux/arm64 --network host --add-host harbor.wldc.site:10.159.16.5 --build-arg HTTP_PROXY=socks5://10.32.4.150:10808 --build-arg HTTPS_PROXY=socks5://10.32.4.150:10808 --build-arg NO_PROXY=localhost,127.0.0.1,.wldc.site,.wldc.site --build-arg http_proxy=socks5://10.32.4.150:10808 --build-arg https_proxy=socks5://10.32.4.150:10808 --build-arg no_proxy=localhost,127.0.0.1,.wldc.site,.wldc.site --push -t harbor.easzlab.io.local/base/buildkit:v0.21.1 .

Dockerfile 文件

FROM moby/buildkit:v0.21.1
# 安装 ca-certificates
RUN apk add --no-cache ca-certificates git
# 复制证书并更新
COPY harbor-ca.crt /usr/local/share/ca-certificates/harbor.crt
RUN update-ca-certificates
RUN mkdir -p /root/.docker
COPY config.json /root/.docker/config.json #config.json 文件是用于buildkit推送到仓库的认证信息通过docker login 以后就会自动创建~/.docker/config.json ,把这个文件copy到与Dockerfile同一目录

二、初始化K8S worker节点支持多架构

  • 在命令行运行如下yaml
kubectl apply -f binfmt-daemonset.yaml #如果所有的pod都Completed以后可以把这个daemonset删除
#binfmt-daemonset.yaml文件内容
apiVersion: apps/v1
kind: DaemonSet
metadata:name: binfmt
spec:selector:matchLabels:name: binfmttemplate:metadata:labels:name: binfmtspec:containers:- name: install-binfmtimage: harbor.easzlab.io.local/base/binfmt:latestargs: ["--install", "all"]securityContext:privileged: true  # 必须:允许加载 binfmt_mischostPID: truerestartPolicy: Never #容器运行以后会成为complete状态,如果再次运行会变成failed状态nodeSelector:kubernetes.io/os: linuxtolerations:- operator: Exists

三、将新创建的buildkit镜像添加到Jenkins的PodTemplate中

  • 在KubeSphere中找到这个配置文件,namespace: kubesphere-devops-system
    在这里插入图片描述
  • 每一个agent模板中都添加buildkit的容器
    在这里插入图片描述
                - name: "buildkit"image: "harbor.easzlab.io.local/base/buildkit:v0.21.1"command: "sleep"args: "infinity"ttyEnabled: trueprivileged: trueresourceRequestCpu: "500m"resourceLimitCpu: "4000m"resourceRequestMemory: "500Mi"resourceLimitMemory: "8192Mi" 
  • 创建buildkit的服务端
kubectl apply -f buildkit-service.yaml -n kubesphere-devops-worker #jenkins流水线启动的pod都在kubesphere-devops-worker 这个空间中,所有服务也创建在这里

buildkit服务文件内容

---
apiVersion: apps/v1
kind: Deployment
metadata:name: buildkitdlabels:app: buildkitd
spec:replicas: 1selector:matchLabels:app: buildkitdtemplate:metadata:labels:app: buildkitdspec:hostAliases:- ip: "10.159.16.5"hostnames:- "harbor.easzlab.io.local"containers:- name: buildkitdimage: harbor.easzlab.io.local/base/buildkit:v0.21.1imagePullPolicy: Alwaysargs:- --addr- unix:///run/buildkit/buildkitd.sock- --addr- tcp://0.0.0.0:1234ports:- containerPort: 1234readinessProbe:exec:command:- buildctl- debug- workersinitialDelaySeconds: 5periodSeconds: 30livenessProbe:exec:command:- buildctl- debug- workersinitialDelaySeconds: 5periodSeconds: 30securityContext:privileged: true
---apiVersion: v1
kind: Service
metadata:name: buildkitdlabels:app: buildkitd
spec:selector:app: buildkitdports:- name: tcpport: 1234targetPort: 1234protocol: TCP
  • 调整流水线的jenkins文件,把之前docker build 和docker push的步骤替换成为buildctl方式,其中一个golang的应用的jenkins文件如下(如果是java的应用不存在判定架构,直接jar包运行在不同的jvm上就可以):
    在这里插入图片描述
pipeline {agent {node {label 'go'  //使用golang的agent,这个agent里面定义了4个容器,分别是base,buildkit,go,jnlp}}stages {stage('clone code') {agent nonesteps {//使base容器把代码拉取到jenkins的cicd worker pod中container('base') {git(url: 'https://git.abc.cn/background/openapi/openapi-front-api.git', credentialsId: 'tenxcloud', branch: '$BRANCH_NAME', changelog: true, poll: false)}}}stage('代码编译') {agent nonesteps {// 使用golang的容器把二进制制品制作出来container('go') {sh '''export GO111MODULE=on
go env -w GOPROXY=http://10.159.1.2:8081/repository/gogroup/,direct
#打包amd64的制品
GOOS=linux 
GOARCH=amd64
go build -mod=vendor -a -v -o app-amd64 main.go
#打包arm64的制品
GOOS=linux 
GOARCH=arm64
go build -mod=vendor -a -v -o app-arm64 main.go'''}}}stage('构建镜像并上传') {agent nonesteps {//使用buildkit 容器构建双架构镜像container('buildkit') {withCredentials([usernamePassword(credentialsId: 'harbor', passwordVariable: 'DOCKER_PASSWORD', usernameVariable: 'DOCKER_USERNAME')]) {sh '''# 生成Dockerfile文件,这个地方需要注意一下命令里面的单引号,双引号和各种转义符,我踩了比较多的坑
tee Dockerfile <<-'EOF'
FROM harbor.easzlab.io.local/base/openeuler:24.03-lts
ARG TARGETARCH
COPY ./app-amd64 /app/app-amd64
COPY ./app-arm64 /app/app-arm64
RUN if [ "\$TARGETARCH" = "amd64" ]; then \mv /app/app-amd64 /app/app; \rm -f  /app/app-arm64; \elif [ "\$TARGETARCH" = "arm64" ]; then \mv /app/app-arm64 /app/app; \rm -f  /app/app-amd64; \else \echo "Unsupported arch: \$TARGETARCH"; \exit -1; \fiCOPY yml /app/yml
WORKDIR /app
RUN chmod +x /app/app
CMD ["/app/app"]
EOFBUILD_TIME=`date +%Y%m%d%H%M%S`
buildctl --addr tcp://buildkitd.kubesphere-devops-worker:1234 build \
--frontend=dockerfile.v0 \
--local context=. \
--local dockerfile=. \
--opt platform=linux/amd64,linux/arm64 \
--output type=image,name=$REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:$BRANCH_NAME-${BUILD_TIME}-$BUILD_NUMBER,push=true
'''}}}}}environment {DOCKER_CREDENTIAL_ID = 'dockerhub'KUBECONFIG_CREDENTIAL_ID = 'kubeconfig'REGISTRY = 'harbor.easzlab.io.local'DOCKERHUB_NAMESPACE = 'release'APP_NAME = 'openapi-front-api'SONAR_CREDENTIAL_ID = 'sonar-token'BUILD_TIME = ''}parameters {string(name: 'BRANCH_NAME', defaultValue: 'master', description: '')}
}
  • 运行流水线,检验多架构的镜像是否上次成功
    在这里插入图片描述
  • 验证多架构镜像,同一个tag,不同得架构都可以拉取成功。
    在这里插入图片描述
    PS: 如有疑问可以仔细看一下整篇文章。如果还是有问题,私信给我,我看到就会回复。

相关文章:

K8S中构建双架构镜像-从零到成功

背景介绍 公司一个客户的项目使用的全信创的环境&#xff0c;服务器采用arm64的机器&#xff0c;而我们的应用全部是amd64的&#xff0c;于是需要对现在公司流水线进行arm64版本的同步镜像生成。本文介绍从最开始到最终生成双架构的全部过程&#xff0c;以及其中使用的相关配置…...

pth的模型格式怎么变成SafeTensors了?

文章目录 背景传统模型格式的安全隐患效率与资源瓶颈跨框架兼容性限制Hugging Face 的解决方案&#xff1a;SafeTensors行业与社区的推动SafeTensors 的意义总结 背景 最近要找一些适合embedding的模型&#xff0c;在huggingface模型库上看到一些排名比较靠前的&#xff0c;准…...

iOS safari和android chrome开启网页调试与检查器的方法

手机开启远程调试教程&#xff08;适用于 Chrome / Safari&#xff09; 前端移动端调试指南&#xff5c;适用 iPhone 和 Android&#xff5c;WebDebugX 出品 本教程将详细介绍如何在 iPhone 和 Android 手机上开启网页检查器&#xff0c;配合 WebDebugX 实现远程调试。教程包含…...

c语言第一个小游戏:贪吃蛇小游戏03

我们为贪吃蛇的节点设置为一个结构体&#xff0c;构成贪吃蛇的身子的话我们使用链表&#xff0c;链表的每一个节点是一个结构体 显示贪吃蛇身子的一个节点 我们这边node就表示一个蛇的身体 就是一小节 输出结果如下 显示贪吃蛇完整身子 效果如下 代码实现 这个hasSnakeNode(…...

​​​​​​​大规模预训练范式(Large-scale Pre-training)

大规模预训练指在巨量无标注数据上&#xff0c;通过自监督学习训练大参数量的基础模型&#xff0c;使其具备通用的表征与推理能力。其重要作用如下&#xff1a; 一 跨任务泛化 单一模型可在微调后处理多种NLP&#xff08;自然语言处理&#xff09;、CV&#xff08;计算机视觉…...

基于Flink的用户画像 OLAP 实时数仓统计分析

1.基于Flink的用户画像 OLAP 实时数仓统计分析 数据源是来自业务系统的T日数据&#xff0c;利用kakfa进行同步 拼接多个事实表形成大宽表&#xff0c;优化多流Join方式&#xff0c;抽取主键和外键形成主外键前置层&#xff0c;抽取外键和其余内容形成融合层&#xff0c;将4次事…...

React Native踩坑实录:解决NativeBase Radio组件在Android上的兼容性问题

React Native踩坑实录&#xff1a;解决NativeBase Radio组件在Android上的兼容性问题 问题背景 在最近的React Native项目开发中&#xff0c;我们的应用在iOS设备上运行良好&#xff0c;但当部署到Android设备时&#xff0c;进入语言设置和隐私设置页面后应用崩溃。我们遇到了…...

iptables实现DDos

最近有客户要定制路由器的默认防火墙等级&#xff0c;然后涉及到了DDos规则&#xff0c;对比客户提供的规则发现我们现有的规则存在明显的错误&#xff0c;在此记录一下如何使用iptables防护DDoS攻击 直接贴一下规则 #开启TCP SYN Cookies 机制 sysctl -w net.ipv4.tcp_synco…...

WPF之高级绑定技术

文章目录 引言多重绑定&#xff08;MultiBinding&#xff09;基本概念实现自定义IMultiValueConverterMultiBinding在XAML中的应用示例使用StringFormat简化MultiBinding 优先级绑定&#xff08;PriorityBinding&#xff09;基本概念PriorityBinding示例实现PriorityBinding的后…...

调出事件查看器界面的4种方法

方法1. 方法2. 方法3. 方法4....

使用vite重构vue-cli的vue3项目

一、修改依赖 首先修改 package.json&#xff0c;修改启动方式与相应依赖 移除vue-cli并下载vite相关依赖&#xff0c;注意一些peerDependency如fast-glob需要手动下载 # 移除 vue-cli 相关依赖 npm remove vue/cli-plugin-babel vue/cli-plugin-eslint vue/cli-plugin-rout…...

Go-GJSON 组件,解锁 JSON 读取新姿势

现在的通义灵码不但全面支持 Qwen3&#xff0c;还支持配置自己的 MCP 工具&#xff0c;还没体验过的小伙伴&#xff0c;马上配置起来啦~ https://click.aliyun.com/m/1000403618/ 在 Go 语言开发领域&#xff0c;json 数据处理是极为常见的任务。Go 标准库提供了 encoding/jso…...

Java详解LeetCode 热题 100(14):LeetCode 56. 合并区间(Merge Intervals)详解

文章目录 1. 题目描述2. 理解题目3. 解法一:排序 + 一次遍历法3.1 思路3.2 Java代码实现3.3 代码详解3.4 复杂度分析3.5 适用场景4. 解法二:双指针法4.1 思路4.2 Java代码实现4.3 代码详解4.4 复杂度分析4.5 与解法一的比较5. 解法三:TreeMap法5.1 思路5.2 Java代码实现5.3 …...

将Docker镜像变为可执行文件?体验docker2exe带来的便捷!

在现代软件开发中,容器化技术极大地改变了应用程序部署和管理的方式。Docker,作为领先的容器化平台,已经成为开发者不可或缺的工具。然而,对于不熟悉Docker的用户来说,接触和运行Docker镜像可能会是一个复杂的过程。为了解决这一问题,docker2exe项目应运而生。它提供了一…...

ev_loop_fork函数

libev监视器介绍&#xff1a;libev监视器用法-CSDN博客 libev loop对象介绍&#xff1a;loop对象-CSDN博客 libev ev_loop_fork函数介绍:ev_loop_fork函数-CSDN博客 libev API吐血整理&#xff1a;https://download.csdn.net/download/qq_39466755/90794251?spm1001.2014.3…...

数据治理域——数据治理体系建设

摘要 本文主要介绍了数据治理系统的建设。数据治理对企业至关重要&#xff0c;其动因包括应对数据爆炸增长、提升内部管理效率、支撑复杂业务需求、加强风险防控与合规管理以及实现数字化转型战略。其核心目的是提升数据质量、统一数据标准、优化数据资产管理、支撑业务发展和…...

ES常识7:ES8.X集群允许4个 master 节点吗

在 Elasticsearch&#xff08;ES&#xff09;中&#xff0c;4 个 Master 节点的集群可以运行&#xff0c;但存在稳定性风险&#xff0c;且不符合官方推荐的最佳实践。以下从选举机制、故障容错、资源消耗三个维度详细分析&#xff1a; 一、4 个 Master 节点的可行性&#xff1…...

onGAU:简化的生成式 AI UI界面,一个非常简单的 AI 图像生成器 UI 界面,使用 Dear PyGui 和 Diffusers 构建。

​一、软件介绍 文末提供程序和源码下载 onGAU&#xff1a;简化的生成式 AI UI界面开源程序&#xff0c;一个非常简单的 AI 图像生成器 UI 界面&#xff0c;使用 Dear PyGui 和 Diffusers 构建。 二、Installation 安装 文末下载后解压缩 Run install.py with python to setup…...

【第52节】Windows编程必学之从零手写C++调试器下篇(仿ollydbg)

目录 一、引言 二、调试器核心功能设计与实现 三、断点功能 四、高级功能 五、附加功能 六、开发环境与实现概要 七、项目展示及完整代码参考 八、总结 一、引言 在软件开发领域&#xff0c;调试器是开发者不可或缺的工具。它不仅能帮助定位代码中的逻辑错误&#xff0…...

uni-app学习笔记五--vue3插值表达式的使用

vue3快速上手导航&#xff1a;简介 | Vue.js 模板语法 插值表达式 最基本的数据绑定形式是文本插值&#xff0c;它使用的是“Mustache”语法 (即双大括号)&#xff1a; <span>Message: {{ msg }}</span> 双大括号标签会被替换为相应组件实例中 msg 属性的值。同…...

C++类与对象(二):六个默认构造函数(一)

在学C语言时&#xff0c;实现栈和队列时容易忘记初始化和销毁&#xff0c;就会造成内存泄漏。而在C的类中我们忘记写初始化和销毁函数时&#xff0c;编译器会自动生成构造函数和析构函数&#xff0c;对应的初始化和在对象生命周期结束时清理资源。那是什么是默认构造函数呢&…...

OpenCV CUDA 模块中在 GPU 上对图像或矩阵进行 翻转(镜像)操作的一个函数 flip()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::cuda::flip 是 OpenCV 的 CUDA 模块中的一个函数&#xff0c;用于在 GPU 上对图像或矩阵进行 翻转&#xff08;镜像&#xff09;操作。它类似…...

基于大模型的原发性醛固酮增多症全流程预测与诊疗方案研究

目录 一、引言 1.1 研究背景与意义 1.2 国内外研究现状 1.3 研究目的与方法 二、原发性醛固酮增多症概述 2.1 疾病定义与发病机制 2.2 临床表现与诊断标准 2.3 流行病学特征 三、大模型预测原理与技术 3.1 大模型简介 3.2 预测原理与算法 3.3 数据收集与预处理 四…...

从逻辑学视角探索数学在数据科学中的系统应用:一个整合框架

声明&#xff1a;一家之言&#xff0c;看个乐子就行。 图表采用了两个维度组织知识结构&#xff1a; 垂直维度&#xff1a;从上到下展示了知识的抽象到具体的演进过程&#xff0c;分为四个主要层级&#xff1a; 逻辑学基础 - 包括数理逻辑框架和证明理论数学基础结构 - 涵盖…...

Matplotlib 完全指南:从入门到精通

前言 Matplotlib 是 Python 中最基础、最强大的数据可视化库之一。无论你是数据分析师、数据科学家还是研究人员&#xff0c;掌握 Matplotlib 都是必不可少的技能。本文将带你从零开始学习 Matplotlib&#xff0c;帮助你掌握各种图表的绘制方法和高级技巧。 目录 Matplotli…...

如何有效追踪需求的实现情况

有效追踪需求实现情况&#xff0c;需要清晰的需求定义、高效的需求跟踪工具、持续的沟通反馈机制&#xff0c;其中高效的需求跟踪工具尤为关键。 使用需求跟踪工具能确保需求实现进度可视化、提高团队协作效率&#xff0c;并帮助识别和管理潜在风险。例如&#xff0c;使用专业的…...

自动驾驶技术栈——DoIP通信协议

一、DoIP协议简介 DoIP&#xff0c;英文全称是Diagnostic communication over Internet Protocol&#xff0c;是一种基于因特网的诊断通信协议。 DoIP协议基于TCP/IP等网络协议实现了车辆电子控制单元(ECU)与诊断应用程序之间的通信&#xff0c;常用于汽车行业的远程诊断、远…...

C++ 与 Go、Rust、C#:基于实践场景的语言特性对比

目录 ​编辑 一、语法特性对比 1.1 变量声明与数据类型 1.2 函数与控制流 1.3 面向对象特性 二、性能表现对比​编辑 2.1 基准测试数据 在计算密集型任务&#xff08;如 10⁷ 次加法运算&#xff09;中&#xff1a; 在内存分配测试&#xff08;10⁵ 次对象创建&#xf…...

Docker 中的 DNS 解析机制

在 Docker 容器化环境中,网络连接是至关重要的,而 DNS(Domain Name System,域名系统)解析则是网络通信的基础。容器需要能够解析内部服务名称以及外部域名,以便与其他容器或外部世界进行交互。理解 Docker 如何处理 DNS 请求,可以帮助我们更好地配置和排查网络问题。 D…...

数字化工厂中央控制室驾驶舱系统 API接口文档

数字化工厂中央控制室驾驶舱系统 API接口文档 本文档详细描述了数字化工厂中央控制室驾驶舱系统的API接口规范&#xff0c;包括中端服务提供的数据接口和算法接口。 1. 通用规范 1.1 基础URL 后端服务: http://localhost:8000中端服务数据API: http://localhost:8001中端服…...