在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(更新…...

Dubbo服务提供者失效踢出原理解析
Dubbo服务提供者失效踢出原理解析 在分布式系统中,服务提供者的失效是一个常见而且重要的问题。Dubbo作为一款优秀的分布式服务框架,提供了失效踢出机制来及时剔除不可用的服务提供者,确保系统的稳定性和可用性。本文将深入探讨Dubbo服务提供…...

el-select下拉框处理分页数据,触底加载更多
1、声明自定义指令: directives: {loadmore: {inserted(el, binding) {const SELECTWRAP_DOM el.querySelector(.el-select-dropdown .el-select-dropdown__wrap);SELECTWRAP_DOM.addEventListener(scroll, function() {const condition this.scrollHeight - thi…...

如何设计自动化测试脚本?一文5个步骤带你从0到1设计
企业中如何设计自动化测试脚本呢?今天我们就来为大家分享一些干货。 一、线性设计 线性脚本设计方式是以脚本的方式体现测试用例,是一种非结构化的编码方式,多数采用录制回放的方式,测试工程师通过录制回访的访问对被测系统进行自…...

PostgreSQL实战-数据库迁移部署
PostgreSQL实战-数据库迁移部署 介绍 根据项目需求,我们需要将现有的PostgreSQL数据库重新部署到新的服务器上。由于项目本身就是基于PostgreSQL数据库构建的,因此数据库迁移将变得十分便捷。接下来,我将简要介绍我们的迁移步骤。 迁移步骤…...

PHP数据库
PHP MySQL 连接数据库 MySQL 简介MySQL Create 免费的 MySQL 数据库通常是通过 PHP 来使用的。 连接到一个 MySQL 数据库 在您能够访问并处理数据库中的数据之前,您必须创建到达数据库的连接。 在 PHP 中,这个任务通过 mysql_connect() 函数完成。 …...

Mybatis的基本操作--增删改查
目录 查看数据 无参数 一个参数 多个参数 添加数据 修改数据 删除数据 注释的方式进行查找数据 查看数据 分三种情况:无参,有一个参数,有多个参数的情况。 (这里的详细操作步骤是博主的上一篇博客写的:初识My…...

Qt简单实现密码器控件
本文实例为大家分享了Qt自定义一个密码器控件的简单实现代码,供大家参考,具体内容如下 实现构思: 密码器的功能可以看成是计算器和登陆界面的组合,所以在实现功能的过程中借鉴了大神的计算器的实现代码和登陆界面实现的代码。 …...

fpga_pwm呼吸灯(EP4CE6F17C8)
文章目录 一、呼吸灯二、代码实现三、引脚分配 一、呼吸灯 呼吸灯是指灯光在微电脑的控制之下完成由亮到暗的逐渐变化,使用开发板上的四个led灯实现1s间隔的呼吸灯。 二、代码实现 c module pwm_led( input clk ,input rst_n ,output reg [3:0] led ); …...

WPF实战学习笔记20-设置首页启动页
文章目录 设置首页启动页增加配置接口添加接口文件:实现接口 配置启动选项 设置首页启动页 增加配置接口 添加接口文件: Mytodo.Common/IConfigureInterface.cs using System; using System.Collections.Generic; using System.Linq; using System.T…...

uniapp实现预约时间选择弹窗组件
做了个组件,实现出当日预约时间组件,效果图如下 废话不多说,直接上代码,代码简单,参数自己任意改 <template><view class"inventory"><u-popup :show"show" :round"10"…...