Go - Variable
内存边界
在编程语言中,为了方便操作内存特定位置的数据,使用变量与特定位置的内存绑定
编译器或者解析器需要知道变量所能引用的内存区域边界
动态语言
解析器可以在运行时通过对变量赋值的分析,自动确定变量的边界
一个变量可以在运行时被赋予大小不同的边界
静态语言
编译器必须明确知道一个变量的边界才允许使用该变量
但编译器无法自动分析,因此边界信息必须由开发者提供 - 变量声明
在具体实现层面,边界信息由变量的类型属性赋予
变量声明
Go 是静态语言,所有变量在使用前必须先进行声明声明:告诉编译器该变量可以操作的内存的边界信息(由变量类型信息提供)
通用
变量声明形式与主流静态语言的差异 - 将变量名放在了类型前面(方便语法糖移除 type)
如果没有显式为变量赋予初值,Go 编译器会为变量赋予类型零值
1var a int // a 的初值为 int 类型的零值 0
Go 的每种原生类型都有其默认值,即类型零值复合类型(array、struct)变量的类型零值为组成元素都为零值的结果
原生类型
类型零值
整型
0
浮点
0.0
布尔
FALSE
字符串
& ...
Go - Web
API
项目结构1234567891011121314151617$ tree.├── cmd│ └── bookstore│ └── main.go├── go.mod├── internal│ └── store│ └── memstore.go├── server│ ├── middleware│ │ └── middleware.go│ └── server.go└── store ├── factory │ └── factory.go └── store.go
逻辑结构
具体实现store
定义 Domain 和 Action
store/store.go12345678910111213141516package storetype Book struct { Id string `json:"id"` Name string `json:"name"` Authors []string `json:"authors& ...
Go - Main + Init
main.main
main 包中的 main 函数 - 所有可执行程序的用户层执行逻辑的入口函数
123456package main// 无参数 + 无返回值func main() { // 用户层执行逻辑}
可执行程序的 main 包必须定义 main 函数,否则会编译报错function main is undeclared in the main package
main.go1package main
123$ go build main.go# command-line-argumentsruntime.main_main·f: function main is undeclared in the main package
在启动了多个 goroutine 的 Go 应用中,main.main 将在 Go 应用的主 goroutine 中执行
main.main 函数返回意味着整个 Go 程序结束
除了 main 包外,其它包也可以拥有自己的 main 函数
但依据 Go 的可见性规则,非 main 包中的 main 函数仅限于包内使用
123456 ...
Go - Go Module
添加依赖
github.com/google/uuid
main.go1234567891011package mainimport ( "github.com/google/uuid" "github.com/sirupsen/logrus")func main() { logrus.Println("hello, gomodule mode") logrus.Println(uuid.NewString())}
go.mod 里的 require 字段中,没有任何 Module 提供了包 github.com/google/uuid
123$ go buildmain.go:4:2: no required module provides package github.com/google/uuid; to add it: go get github.com/google/uuid
手动 go get,下载依赖到本地 Module 缓存,并更 ...
Go - Build Mode
构建过程
确定包版本 + 编译包 + 链接目标文件(编译后得到的)
构建模式
Mode
Desc
GOPATH
不关注依赖版本
Vendor - 1.5
Reproducible Build
Go Module - 1.11
Dependency Management
GOPATH
Go 首次开源时,内置了 GOPATH 的构建模式
Go 编译器可以在本地 GOPATH 下搜索 Go 程序依赖的第三方包
如果存在,则使用这个本地包进行编译;如果不存在,则会报编译错误
main.go1234567package mainimport "github.com/sirupsen/logrus"func main() { logrus.Println("hello, gopath mode")}
无法找到依赖包而构建失败
1234567891011121314151617$ go versiongo version go1.10.8 linux/amd64$ echo $GOROOT/home/zhongming ...
Go - Project Layout
演进历史Go 1.3
以 all.bash 为代表的源码构建脚本放在了 src 的顶层目录下
123456789101112131415161718192021222324$ tree -LF 1 ./src./src/├── Make.dist├── all.bash*├── all.bat├── all.rc*├── clean.bash*├── clean.bat├── clean.rc*├── cmd/├── lib9/├── libbio/├── liblink/├── make.bash*├── make.bat├── make.rc*├── nacltest.bash*├── pkg/├── race.bash*├── race.bat├── run.bash*├── run.bat├── run.rc*└── sudo.bash*
./src/cmd 存放着 Go 可执行文件的相关目录,每个子目录都是一个 Go 工具链命令或子命令对应的可执行文件
12345678910111213141516171819$ tree -LF 1 ./src/cmd./src/cmd/├── 5a/ ...
Go - Code Structure
源文件
Go 源文件使用全小写字母形式的短小单词命名,并以 .go 扩展名结尾
如果使用多个单词,将多个单词直接连接起来,而不使用其它分隔符
即 helloworld.go,而非 hello_world.go
尽量不要使用两个以上单词组合作为文件名,否则很难辨认
Hello, World1234567package mainimport "fmt"func main() { fmt.Println("Hello, World!")}
12345678910111213$ tree.└── main.go$ go build main.go$ tree.├── main└── main.go$ ./mainHello, World!
程序结构1package main
package 是 Go 语言的基本组成单位,通常使用单个小写单词命名
整个 Go 程序仅允许存在一个 main 包
main.go12345import "fmt"func main() { fmt.Println(&quo ...
Kubernetes - DevOps
基本概念流程概览
实现自动化,最核心的投入为编写测试用例
分支管理
提交 PR 时会触发 CI Pipeline;生产系统版本不能直接使用 master 分支(最新代码),而是要基于 Release 分支
CICD
CI
CD
GitOps
一切皆代码,通过 Git 来触发 Ops
Jenkins
Jenkins 不是云原生
Container CI
需要保证 CI 构建环境和开发环境的统一
使用容器作为标准的构建环境,将代码库作为 Volume 挂载进容器
需要在构建容器中执行 docker build 命令,即 Docker in Docker = DIND
Kubernetes CI
Jenkins 可以被容器化(on Kubernetes),并支持 Cloud Provider,通过插件的方式支持 Kubernetes
https://github.com/jenkinsci/kubernetes-pluginJenkins plugin to run dynamic agents in a Kubernetes/Docker environment
...
Kubernetes - Production Ops
镜像仓库
镜像仓库(Registry)负责存储、管理和分发镜像
Registry 管理多个 Repository(通过命名区分)
每个 Repository 包含一个或多个镜像(通过镜像名和标签区分)
客户端拉取镜像:Registry/Repository/Image:Tag
分发规范
镜像仓库应遵循 OCI Distribution Spec
HTTP Verb
URL
Desc
GET
/v2/
检查 Registry 实现的规范和版本
GET
/v2/_catalog
获取 Repository 列表
GET
/v2//tags/list
获取某个 Repository 下所有的标签
PUT
/v2//manifests/
上传 Image 的 manifest 信息
DELETE
/v2//manifests/
删除 Image
GET
/v2//manifests ...
Kubernetes - Manage Production Clusters
操作系统
通用操作系统 - 成熟
Ubuntu
CentOS
Fedora
专为容器优化的操作系统 - 最小化主机操作系统
CoreOS
最早的容器化操作系统,已被收购
RedHat Atomic
将 RPM Repository 转换成 ostree,可以被 bootloader 直接加载
Snappy Ubuntu Core
Canonical 出品,最初为移动设备设计
RancherOS
相对较新,RancherOS 中运行的所有服务都是 Docker 容器
评估选型的标准
是否有生态系统
成熟度
内核版本
对运行时的支持
Init System
包管理和系统升级
安全
不可变基础设施
不可变的容器镜像
不可变的主机操作系统
Atomic - 打包成一个经过裁剪后的操作系统
由 Red Hat 支持的软件包安装系统
多种发行版:Fedora / CentOS / RHEL
优势
不可变操作系统,面向容器优化的基础设施
只有 /etc 和 /var 可以修改,其它目录均为只读
基于 rpm-ostree 管理系统包
IaC:输 ...