在CSDN学Golang云原生(Docker镜像)
一,镜像分层机制
在 Docker 中,一个镜像可以由多个分层(Layer)组成。每个分层都表示一些修改或添加到上一个分层的文件系统差异。
Golang 在构建 Docker 镜像时也支持类似的机制,通过 docker build
命令来创建一个包含多个分层的镜像。
具体实现方式是在 Dockerfile 中使用 RUN
、ADD
、COPY
等指令来安装软件包、下载文件等操作,并且使用 -o
选项设置编译输出目录:
FROM golang:1.16WORKDIR /go/src/appCOPY . .RUN go get -d -v ./...
RUN go install -v ./...CMD ["app"]
上面的例子中,我们从 Golang 官方镜像开始构建一个新镜像,并设置工作目录为 /go/src/app
。然后复制当前目录下所有文件到容器中,并执行 go get
和 go install
命令安装和编译 Go 代码。最后设置容器启动命令为 app
。
在执行这个 Dockerfile 的过程中,Docker 会将每个指令生成的结果保存为一个新的分层,并将它们合并成最终的镜像。这种机制有助于减小镜像大小,避免重复数据存储。
如果你想查看某个 Docker 镜像的所有分层信息,可以使用 docker history
命令:
$ docker history my-image
IMAGE CREATED CREATED BY SIZE COMMENT
d34e5b1a58b3 5 days ago /bin/sh -c #(nop) CMD ["app"] 0B
<missing> 5 days ago /bin/sh -c go install -v ./... 4.57MB
<missing> 5 days ago /bin/sh -c go get -d -v ./... 43.9MB
<missing> 5 days ago /bin/sh -c #(nop) COPY dir:86fd420f94bef8f09... 2.61kB
<missing> 6 weeks ago /bin/sh -c #(nop) WORKDIR /go/src/app 0B
<missing> 6 weeks ago /bin/sh -c #(nop) COPY file:d75a3e0d6401fcdb7... 116B
<missing> 6 weeks ago /bin/sh -c #(nop) CMD ["bash"] 0B
<missing> 6 weeks ago /bin/sh -c #(nop) ADD file:e0da07f59373bac823... 811MB
上面的结果显示了该镜像中每个分层所包含的文件、大小以及生成方式。
需要注意的是,由于 Docker 镜像的设计原理,某些操作(例如 apt-get update
)可能会导致多次创建分层,从而增加镜像大小。因此在编写 Dockerfile 的时候要尽量避免重复或无效的操作,以减小镜像大小。
二,容器写时复制机制
Golang 容器写时复制(Copy-on-write) 的实现细节,以下是一个简单的代码示例:
func CopyContainer(rootfs string) (string, error) {// 创建容器镜像的只读层runcmd := exec.Command("docker", "create", rootfs)output, err := runcmd.Output()if err != nil {return "", fmt.Errorf("failed to create container: %v", err)}containerID := strings.TrimSpace(string(output))// 挂载容器镜像到一个临时目录tmpdir, err := ioutil.TempDir("", "container")if err != nil {return "", fmt.Errorf("failed to create temporary directory: %v", err)}defer os.RemoveAll(tmpdir)mountcmd := exec.Command("mount", "-o", "bind", "/proc/self/mounts", filepath.Join(tmpdir, "mounts"))if err := mountcmd.Run(); err != nil {return "", fmt.Errorf("failed to mount /proc/self/mounts: %v", err)}// 以只读方式挂载容器层到临时目录rootfsPath := filepath.Join(tmpdir, "rootfs")if err := os.MkdirAll(rootfsPath, 0755); err != nil {return "", fmt.Errorf("failed to create rootfs path: %v", err)}mountcmd = exec.Command("mount", "-o", "ro,noatime,nodiratime,noexec,nodev,nosuid", "--bind", rootfs, rootfsPath)if err := mountcmd.Run(); err != nil {return "", fmt.Errorf("failed to bind mount rootfs: %v", err)}// 创建容器镜像的读写层layerPath := filepath.Join(tmpdir, "layer")if err := os.MkdirAll(layerPath, 0755); err != nil {return "", fmt.Errorf("failed to create layer path: %v", err)}// 挂载读写层到容器镜像只读层上mountcmd = exec.Command("mount", "-o", "rw,noatime,nodiratime,noexec,nodev,nosuid,lowerdir="+rootfsPath+",upperdir="+layerPath+",workdir="+filepath.Join(tmpdir, "work"), "none", filepath.Join(tmpdir, "overlay"))if err := mountcmd.Run(); err != nil {return "", fmt.Errorf("failed to create overlay mount: %v", err)}// 卸载临时目录下挂载的文件系统defer func() {exec.Command("umount", "-l", filepath.Join(tmpdir, "overlay")).Run()exec.Command("umount", "-l", rootfsPath).Run()exec.Command("umount", "-l", filepath.Join(tmpdir, "mounts")).Run()}()containerRoot := filepath.Join(layerPath, "root")return containerRoot, nil
}
此函数使用 Golang 的 os/exec
包来执行操作系统级别的命令(如挂载和卸载文件系统)。它首先创建一个只读的容器镜像,并将其挂载到一个临时目录。然后,它将容器镜像根文件系统以只读方式挂载到该临时目录中,然后再将读写层作为 OverlayFS 挂载到只读层上。最后,它返回容器的根路径。
需要注意的是,此示例仅适用于 Linux 系统,并且使用了一些操作系统特定的命令和选项。在不同的操作系统和环境中可能需要进行修改以实现类似的功能。
三,容器联合挂载机制
在Golang中,可以通过使用os/exec包和容器运行时接口(CRI)来实现容器的联合挂载机制。
具体步骤如下:
- 使用os/exec包创建一个新的进程,并设置其命令参数为需要执行的容器程序。
- 在命令参数中指定需要挂载的文件系统类型及其路径,例如:--mount type=bind,source=/host/path,target=/container/path
- 使用CRI将该进程作为容器启动起来。
- 容器内部可以访问到宿主机上已经挂载好的目录,即实现了联合挂载。
示例代码如下:
package mainimport ("os""os/exec"
)func main() {cmd := exec.Command("docker", "run", "--rm","-v", "/etc:/host/etc:ro","alpine", "cat", "/host/etc/hostname")cmd.Stdout = os.Stdoutcmd.Stderr = os.Stderrerr := cmd.Run()if err != nil {panic(err)}
}
以上代码会启动一个Alpine Linux容器,并且将宿主机上的/etc目录以只读方式挂载到容器内部。然后在容器内部执行cat /host/etc/hostname命令,输出宿主机上的主机名信息
四,镜像内容寻址机制
在golang中,镜像内容寻址机制指的是程序在运行时如何查找和访问已经编译好的包文件。golang使用了一种基于包名的寻址机制。
当我们在代码中引用一个外部包时,例如import "fmt"
,编译器会首先查找系统上的标准库路径,如果找到了就直接使用系统自带的fmt包;如果没有找到,则会继续在$GOPATH环境变量所指向的目录下查找,并将其编译成二进制文件进行链接。若还未找到,则会报错提示无法找到对应包。
Golang对于不同操作系统采用了不同的命名规范和后缀名。例如,在Windows平台下生成的可执行文件为.exe格式,在Linux或Unix平台下则是二进制可执行文件。
golang通过基于包名和路径来确定应该从哪个位置加载相应的包,这种方式使得依赖管理更加简单易懂,同时也方便了跨平台开发。
五,镜像构建
Golang 镜像构建通常可以分为以下几个步骤:
- 编写Dockerfile文件:Dockerfile是构建镜像的配置文件,其中包含了一系列命令和指令,用于指定如何将代码打包进镜像中。例如,可以通过
FROM
指令指定基础镜像(例如golang:latest
);通过WORKDIR
指令设置工作目录;通过COPY
或者ADD
指令将代码拷贝到镜像中等。 - 构建Docker镜像:在终端窗口中使用docker build命令来执行构建过程。例如:
docker build -t my-golang-app .
这条命令会在当前目录下寻找名为“Dockerfile”的文件,并以此为依据构建新的my-golang-app镜像。
- 运行容器:在终端窗口中使用docker run命令运行容器。例如:
docker run -p 8080:8080 my-golang-app
这样就成功运行了一个 Golang 应用程序的 Docker 容器,并且可以通过浏览器访问 http://localhost:8080 来查看应用程序的输出。
需要注意的是,在编写 Dockerfile 文件时,应该尽量遵循最佳实践,避免一些常见问题,如不必要的安装软件包、不规范的文件权限等。
六,镜像共享
Golang 镜像共享一般有两种方式:
- 通过 Docker Hub 共享:Docker Hub 是官方的 Docker 镜像仓库,开发者可以在其中创建自己的镜像并分享给其他人。要实现这种方式,需要在 Docker Hub 上注册账号,并将自己的 Golang 镜像 push 到 Docker Hub 上去,然后其他用户就可以 pull 下来使用。
- 通过私有镜像仓库共享:如果不想将自己的 Golang 镜像公开分享到 Docker Hub 上,也可以搭建自己的私有镜像仓库(如 Harbor、Nexus等),将其作为公司或团队内部的镜像管理中心,以便于内部协同开发和部署应用程序。在私有镜像仓库中上传和下载 Golang 镜像与在 Docker Hub 中类似。
无论是哪种方式,都需要遵循最佳实践制作好 Golang 镜像,并确保该镜像具有较高的可重复性和稳定性,在生产环境中能够正常运行。
七,私有注册中心构建
在 Golang 中,可以使用 Docker 镜像仓库或者自己搭建私有注册中心来进行镜像的管理和共享。下面介绍一种基于 Harbor 的私有注册中心构建方式。
- 下载安装并启动 Harbor
在官网下载 Harbor 并解压缩到任意目录,然后运行./install.sh
脚本安装。安装完毕后执行docker-compose up -d
启动 Harbor。默认情况下 Harbor 运行在 80 和 443 端口上,并使用自签名证书加密通信。 - 创建项目并添加用户
登录到 Harbor 控制台,在左侧导航栏选择“项目”,点击“新建项目”按钮创建一个新的项目。然后在该项目中创建用户并分配权限,以便于其他人上传、下载和管理镜像。 - 构建 Golang 镜像并 push 到 Harbor
编写一个简单的 Golang 应用程序,并编译成可执行文件(例如 hello-world),然后写好 Dockerfile 文件并将其与可执行文件放在同一目录下。接着在该目录下执行以下命令:
# 使用 Dockerfile 构建镜像
docker build -t harbor.example.com/myproject/hello-world:v1 .# 将镜像推送到 Harbor 私有注册中心
docker push harbor.example.com/myproject/hello-world:v1
其中 harbor.example.com
是你的私有注册中心地址,myproject
是你创建的项目名称,hello-world:v1
是镜像的名称和版本号。
- 下载并使用 Golang 镜像
在其他机器上登录到 Harbor 控制台或者运行以下命令下载镜像:
docker login harbor.example.com
docker pull harbor.example.com/myproject/hello-world:v1
然后就可以使用该镜像了。
注意:为了保证安全性和可靠性,在实际生产环境中,需要对私有注册中心进行更多的配置和管理,例如设置访问控制、加密通信、备份恢复等。
相关文章:
在CSDN学Golang云原生(Docker镜像)
一,镜像分层机制 在 Docker 中,一个镜像可以由多个分层(Layer)组成。每个分层都表示一些修改或添加到上一个分层的文件系统差异。 Golang 在构建 Docker 镜像时也支持类似的机制,通过 docker build 命令来创建一个包…...
Hive窗口函数大全
Hive窗口函数 一、偏移量函数laglead 二、窗口分析函数first_valuelast_value 三、排序函数rankdense_rankrow_number 一、偏移量函数 lag 语法:lag(col,n,default_val) 返回值:字段类型 说明:往前第n行数据。 lag(column字段,第…...

达闼面试(部分)(未完全解析)
grpc怎么解决负载均衡问题? Answer by newBing : gRPC提供了多种负载均衡策略,包括轮询、随机、最少连接数等。gRPC客户端可以使用这些策略来选择要连接的服务器。 k8s环境下部署grpc的几种方案 : 在k8s环境中,可以选择headless service,或者…...

Makefile常用函数
目录 字符串替换函数:subst 模式字符串替换函数:patsubst 去空格函数 strip 查找字符串函数 findstring 过滤函数 filter 反过滤函数 filter-out 排序函数 sort 取目录函数 dir 取文件函数 notdir 取后缀函数 suffix 取前缀函数 basename 加…...

mysql的一些知识整理
这里整理一些mysql相关的知识点,是自己不太熟悉的内容 varchar(n) 中 n 最大取值为多少 MySQL 规定除了 TEXT、BLOBs 这种大对象类型之外,其他所有的列(不包括隐藏列和记录头信息)占用的字节长度加起来不能超过 65535 个字节。 …...

修改密码和再次确认密码的js和element-ui的使用
<template><div><!-- plan的插槽 --><plan title"修改密码"><!-- 插槽的名字 --><span slot"header">修改密码</span><el-form:model"ruleForm2"status-icon:rules"rules2"ref"rul…...

蓝桥杯专题-真题版含答案-【垒骰子_动态规划】【抽签】【平方怪圈】【凑算式】
点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 👉关于作者 专注于Android/Unity和各种游…...
kubernetes调试利器——kubectl debug工具
通常情况下,业务容器所使用的镜像是非常精简的,而一旦业务容器出现问题,通过kubectl exec进入到容器时,我们会发现自己需要使用的工具都没有,也无法通过apt, apt-get, yum等包管理工具下载需要的工具。 想要解决这个尴…...

浅谈es5如何保证并发请求的返回顺序
最近在公司实习写的是es5,在和回调地狱经过一番拉扯之后写下这篇文章,也算是体验了一把没有promise的时代 假设我们的div有一个日历列表,但是由于大小关系只能每次显示2天的信息,项目限制只能使用es5,不能使用es6的pro…...
深入浅出Pytorch函数——torch.squeeze
分类目录:《深入浅出Pytorch函数》总目录 相关文章: 深入浅出Pytorch函数——torch.squeeze 深入浅出Pytorch函数——torch.unsqueeze 将输入张量形状为1的维度去除并返回。比如输入向量的形状为 A 1 B 1 C 1 D A\times1\times B\times1\times C…...
【LeetCode】121.买卖股票的最佳时机
题目 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从这笔交易中获取的最大…...
【力扣】74. 搜索二维矩阵 <二分法>
【力扣】74. 搜索二维矩阵 给你一个满足下述两条属性的 m x n 整数矩阵: 每行中的整数从左到右按非递减顺序排列。每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target ,如果 target 在矩阵中,返回 true ;否则&am…...
Spring Task+Cron表达式
不需要导入坐标spring-context(包含在了spring-boot-starter) 在启动类添加EnableScheduleing开启任务调度 单独建个定时任务包task,创建定时任务类MyTask 在定时任务类添加Component 在类的方法上添加Scheduled(cron “cron表达…...

你们公司的【前端项目】是如何做测试的?字节10年测试经验的我这样做的...
前端项目也叫web端项目(通俗讲就是网页上的功能)是我们能够在屏幕上看到并产生交互的体验。 前端项目如何做测试? 要讲清楚这个问题,先需要你对测试流程现有一个全局的了解,先上一张测试流程图: 测试流程…...

华为战略方法论:BLM模型之关键任务与依赖关系
内容简介 在 BLM 模型中,执行部分包括四个模块,分别是: 关键任务与依赖关系;组织与绩效;人才;氛围与文化。 详细内容,大家可以参看下面这张图。 这四个模块其实是可以进一步划分成两个关键点…...
django的ORM模板的fake更新
django存量数据表的migraions记录丢失,若要更新表结构,则需用到fake,否则报错: 解决步骤如下: 1)同步存量表结构,生成伪表 --fake sudo python3 manage.py makemigrations appname sudo pyt…...

239.滑动窗口最大值
leetcode原题链接 题目描述: 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 示例1: 输入:nums [1,…...
Redis基础原理
1 概念 1.1 关系型数据库与非关系型数据库对比 关系型数据库Mysql、Oralce特点数据之间有关联;数据存储在硬盘上效率操作关系型数据库非常耗时 非关系型数据库redis、hbase存储key:value特点数据之间没有关联关系;数据存储在内存中缓存思想从缓存中获…...
.NET 5 Web API 中JWT详细教程:保护你的Web应用
第一部分: 理解JWT JSON Web Token(JWT)是一种在不同系统之间传递信息的安全方式。它由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。头部包…...

MyBatis-Plus自动填充
文章目录 一、前言二、MyBatis-Plus自动填充功能实现2.1、实体类上增加注解2.2、自定义填充类编写 一、前言 我们在建表的时候,所有的表都会有create_id(创建人id)、create_time(创建时间)、update_id(更新…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南
文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果
selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...

Web后端基础(基础知识)
BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。 优点:维护方便缺点:体验一般 CS架构:Client/Server,客户端/服务器架构模式。需要单独…...
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么?它的作用是什么? Spring框架的核心容器是IoC(控制反转)容器。它的主要作用是管理对…...

链式法则中 复合函数的推导路径 多变量“信息传递路径”
非常好,我们将之前关于偏导数链式法则中不能“约掉”偏导符号的问题,统一使用 二重复合函数: z f ( u ( x , y ) , v ( x , y ) ) \boxed{z f(u(x,y),\ v(x,y))} zf(u(x,y), v(x,y)) 来全面说明。我们会展示其全微分形式(偏导…...