大家好,我是腾意。
Golang 究竟是什么呢? Golang 应该如何安装使用?下面我带你一一学习。
Golang 是什么?
Golang 又称为 Go,是 Google 开源的一种静态编译型语言,Golang 自带内存管理机制,相比于 C 和 C++ 语言,我们不需要关心内存的分配和回收。
Golang 是新一代的互联网编程语言,在 Golang 诞生前,C 或 C++ 作为服务端高性能编程语言,使用 C 或 C++ 开发的业务具有非常高的执行效率,但是编译和开发效率却不尽人意,Java、.NET 等语言的诞生大大提高了软件开发速度,但是运行效率和资源占用却不如 C 和 C++。
这时 Golang 横空出世,由于 Golang 较高的开发效率和执行效率,很快便从众多编程语言中脱颖而出,成为众多互联网公司的新宠儿。滴滴、知乎、阿里等众多大型互联网公司都在大量使用 Golang。 同时,Docker 和 Kubernetes 等众多明星项目也都是使用 Golang 开发的。因此,熟练掌握 Golang 将会为你加分很多。
这么好的编程语言,你是不是已经迫不及待地想要安装体验一下了?别着急,下面我带你来安装一个 Golang 环境。
Golang 安装
安装信息如下:
- CentOS 7系统
- Golang 版本 1.15.2
首先我们到Golang 官网(由于国内无法访问 Golang 官网,推荐到Golang 中文网下载安装包)下载一个对应操作系统的安装包。
$ cd /tmp && wget https://studygolang.com/dl/golang/go1.15.2.linux-amd64.tar.gz
解压缩安装包:
$ sudo tar -C /usr/local -xzf go1.15.2.linux-amd64.tar.gz
在 $HOME/.bashrc 文件末尾添加以下内容,将 Golang 可执行文件目录添加到系统 PATH 中:
export PATH=$PATH:/usr/local/go/bin
将 go 的安装路径添加到系统 PATH 中后,就可以在命令行直接使用 go 命令了。配置好 go 命令后,我们还需要配置 GOPATH 才能正确存放和编译我们的 go 代码。
配置 GOPATH
GOPATH 是 Golang 的源码和相关编译文件的存放路径,GOPATH 路径下有三个文件夹 src、pkg 和 bin,它们的用途分别是:
目录 | 用途 |
---|---|
src | 源代码存放路径或者引用的外部库 |
pkg | 编译时生成的对象文件 |
bin | 编译后的可执行二进制 |
这里我们开始配置 GOPATH 路径为 /go。首先准备相关的目录:
$ sudo mkdir /go $ sudo mkdir /go/src $ sudo mkdir /go/pkg $ sudo mkdir /go/bin
然后将 GOPATH 添加到 $HOME/.bashrc 文件末尾,并且把 GOPATH 下的 bin 目录也添加到系统的 PATH 中,这样方便程序编译后直接使用。添加的内容如下:
export GOPATH=/go export PATH=$PATH:$GOPATH/bin # 设置 Golang 的代理,方便我们顺利下载依赖包 export GOPROXY="https://goproxy.io,direct"
接下来,使用 source $HOME/.bashrc 命令生效一下我们的配置,然后我们再使用 go env 命令查看一下我们的配置结果:
$ go env GO111MODULE="" GOARCH="amd64" GOBIN="" GOCACHE="/root/.cache/go-build" GOENV="/root/.config/go/env" GOEXE="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="linux" GOINSECURE="" GOMODCACHE="/go/pkg/mod" GONOPROXY="" GONOSUMDB="" GOOS="linux" GOPATH="/go" GOPRIVATE="" GOPROXY="https://goproxy.io,direct" GOROOT="/usr/local/go" GOSUMDB="sum.golang.org" GOTMPDIR="" GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64" GCCGO="gccgo" AR="ar" CC="gcc" CXX="g++" CGO_ENABLED="1" GOMOD="" CGO_CFLAGS="-g -O2" CGO_CPPFLAGS="" CGO_CXXFLAGS="-g -O2" CGO_FFLAGS="-g -O2" CGO_LDFLAGS="-g -O2" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build352828668=/tmp/go-build -gno-record-gcc-switches"
从 GOPATH 和 GOPROXY 两个变量的结果,可以看到 GOPATH 和 GOPROXY 均已经生效。到此,我们的 Golang 已经安装完毕。下面,我们就开始真正的 Docker 编写之旅吧。
编写 Docker
在开始编写 Docker 之前,我先介绍几个基础知识,如果你对这些基础知识已经很熟悉了,可以直接跳过这块的基础知识。
Linux Proc 文件系统
Linux 系统中,/proc 目录是一种“文件系统”,这里我用了引号,其实 /proc 目录并不是一个真正的文件系统。/proc 目录存放于内存中,是一个虚拟的文件系统,该目录存放了当前内核运行状态的一系列特殊的文件,你可以通过这些文件查看当前的进程信息。
下面,我们通过 ls 命令查看一下 /proc 目录下的内容:
$ sudo ls -l /proc total 0 dr-xr-xr-x 9 root root 0 Sep 19 21:34 1 dr-xr-xr-x 9 root root 0 Sep 19 21:34 30097 ...省略部分输出 dr-xr-xr-x 9 root root 0 Sep 19 21:34 8 dr-xr-xr-x 9 root root 0 Sep 19 21:34 9 dr-xr-xr-x 9 root root 0 Sep 19 21:34 97 dr-xr-xr-x 2 root root 0 Sep 19 22:27 acpi -r--r--r-- 1 root root 0 Sep 19 22:27 buddyinfo dr-xr-xr-x 4 root root 0 Sep 19 22:27 bus -r--r--r-- 1 root root 0 Sep 19 22:27 cgroups -r--r--r-- 1 root root 0 Sep 19 22:27 cmdline -r--r--r-- 1 root root 0 Sep 19 22:27 consoles -r--r--r-- 1 root root 0 Sep 19 22:27 cpuinfo -r--r--r-- 1 root root 0 Sep 19 22:27 crypto -r--r--r-- 1 root root 0 Sep 19 22:27 devices -r--r--r-- 1 root root 0 Sep 19 21:34 diskstats -r--r--r-- 1 root root 0 Sep 19 22:27 dma dr-xr-xr-x 2 root root 0 Sep 19 22:27 driver -r--r--r-- 1 root root 0 Sep 19 22:27 execdomains -r--r--r-- 1 root root 0 Sep 19 22:27 fb -r--r--r-- 1 root root 0 Sep 19 22:27 filesystems dr-xr-xr-x 5 root root 0 Sep 19 22:27 fs -r--r--r-- 1 root root 0 Sep 19 22:27 interrupts -r--r--r-- 1 root root 0 Sep 19 22:27 iomem -r--r--r-- 1 root root 0 Sep 19 22:27 ioports dr-xr-xr-x 27 root root 0 Sep 19 22:27 irq -r--r--r-- 1 root root 0 Sep 19 22:27 kallsyms -r-------- 1 root root 140737486266368 Sep 19 22:27 kcore -r--r--r-- 1 root root 0 Sep 19 22:27 key-users -r--r--r-- 1 root root 0 Sep 19 22:27 keys -r-------- 1 root root 0 Sep 19 22:27 kmsg -r-------- 1 root root 0 Sep 19 22:27 kpagecount -r-------- 1 root root 0 Sep 19 22:27 kpageflags -r--r--r-- 1 root root 0 Sep 19 22:27 loadavg -r--r--r-- 1 root root 0 Sep 19 22:27 locks -r--r--r-- 1 root root 0 Sep 19 22:27 mdstat -r--r--r-- 1 root root 0 Sep 19 22:27 meminfo -r--r--r-- 1 root root 0 Sep 19 22:27 misc -r--r--r-- 1 root root 0 Sep 19 22:27 modules lrwxrwxrwx 1 root root 11 Sep 19 22:27 mounts -> self/mounts -rw-r--r-- 1 root root 0 Sep 19 22:27 mtrr lrwxrwxrwx 1 root root 8 Sep 19 22:27 net -> self/net -r--r--r-- 1 root root 0 Sep 19 22:27 pagetypeinfo -r--r--r-- 1 root root 0 Sep 19 22:27 partitions -r--r--r-- 1 root root 0 Sep 19 22:27 sched_debug -r--r--r-- 1 root root 0 Sep 19 22:27 schedstat dr-xr-xr-x 2 root root 0 Sep 19 22:27 scsi lrwxrwxrwx 1 root root 0 Sep 19 21:34 self -> 30097 -r-------- 1 root root 0 Sep 19 22:27 slabinfo -r--r--r-- 1 root root 0 Sep 19 22:27 softirqs -r--r--r-- 1 root root 0 Sep 19 21:34 stat -r--r--r-- 1 root root 0 Sep 19 21:34 swaps dr-xr-xr-x 1 root root 0 Sep 19 21:34 sys --w------- 1 root root 0 Sep 19 22:27 sysrq-trigger dr-xr-xr-x 2 root root 0 Sep 19 22:27 sysvipc -r--r--r-- 1 root root 0 Sep 19 22:27 timer_list -rw-r--r-- 1 root root 0 Sep 19 22:27 timer_stats dr-xr-xr-x 4 root root 0 Sep 19 22:27 tty -r--r--r-- 1 root root 0 Sep 19 22:27 uptime -r--r--r-- 1 root root 0 Sep 19 22:27 version -r-------- 1 root root 0 Sep 19 22:27 vmallocinfo -r--r--r-- 1 root root 0 Sep 19 22:27 vmstat -r--r--r-- 1 root root 0 Sep 19 22:27 zoneinfo
可以看到,这个目录下有很多数字,这些数字目录实际上是以进程 ID 命名的。除了这些以进程 ID 命名的目录,还有一些特殊的目录,这里我讲解一下与我们编写 Docker 有关的文件和目录。
- self 目录:它是连接到当前正在运行的进程目录,比如我当前的进程 ID 为 30097,则 self 目录实际连接到 /proc/30097 这个目录。
- /proc/{PID}/exe 文件:exe 连接到进程执行的命令文件,例如 30097 这个进程的运行命令为 docker,则执行 /proc/30097/exe ps 等同于执行 docker ps。
好了,了解完这些基础知识后,我们就开始行动吧!因为我们的精简版 Docker 是使用 Golang 编写,这里就给我们编写的 Docker 命名为 gocker 吧。
实现 gocker 的 run 命令
通过前面的章节,我们学习了要运行一个容器,必须先有镜像。这里我们首先准备一个 busybox 镜像,以便我们运行 gocker 容器。
$ mkdir /tmp/busybox && cd /tmp/busybox $ docker export $(docker create busybox) -o busybox.tar $ tar -xf busybox.tar
以上是我们在 /tmp/busybox 目录,使用 docker export 命令导出的一个 busybox 镜像文件,然后对镜像文件包进行解压,解压后 /tmp/busybox 目录内容如下:
$ ls -l /tmp/busybox/ total 1472 drwxr-xr-x 2 root root 12288 Sep 9 02:09 bin -rw------- 1 root root 1455104 Sep 19 22:47 busybox.tar drwxr-xr-x 4 root root 4096 Sep 19 16:41 dev drwxr-xr-x 3 root root 4096 Sep 19 16:41 etc drwxr-xr-x 2 nfsnobody nfsnobody 4096 Sep 9 02:09 home drwxr-xr-x 2 root root 4096 Sep 19 16:41 proc drwx------ 2 root root 4096 Sep 19 21:07 root drwxr-xr-x 2 root root 4096 Sep 19 16:41 sys drwxrwxrwt 2 root root 4096 Sep 9 02:09 tmp drwxr-xr-x 3 root root 4096 Sep 9 02:09 usr drwxr-xr-x 4 root root 4096 Sep 9 02:09 var
准备好镜像文件后,把我为你准备好的 gocker 代码下载下来吧,这里我使用手动下载源码的方式克隆代码:
$ mkdir -p /go/src/github.com/bianchengvip $ cd /go/src/github.com/bianchengvip && git clone https://github.com/bianchengvip/gocker.git $ cd gocker $ git checkout
我的 GOPATH 在 /go 目录下,如果你的 GOPATH 跟我不一致,请根据 GOPATH 存放和编译源码。本课时的源码存放在这里,你也可以在线阅读。
代码下载完后,我们进入 gocker 的目录,查看下源码文件:
$ tree . . |-- go.mod |-- go.sum |-- main.go |-- README.md |-- runc | `-- run.go `-- vendor ... 省略 vendor 目录结构 15 directories, 59 files
本项目使用 go mod 管理包依赖,go mod 是在 golang 1.11 版本加入的新的特性,是用来管理包的依赖的,也是目前官方的包依赖管理工具。如果你想学习更多个 go mod 使用方法,可以参考官网。
可以看到该源码下有两个主要文件:一个是 main.go 文件,这是 gocker 的主入口函数;另外一个是 run.go ,这个文件是 gocker run 命令的具体实现。
下面我们使用 go install 命令来编译一下我们的 gocker 项目:
$ go install
执行完 go install 后, Golang 会自动帮助我们编译当前项目下的代码,编译后的二进制文件存放在 $GOPATH/bin 目录下。由于我们之前在 $HOME/.bashrc 文件下把 $GOPATH/bin 放入了系统 PATH 中,所以此时你可以直接使用 gocker 命令了。 接下来我们使用 gocker 来启动一个容器:
# gocker run -it -rootfs=/tmp/busybox /bin/sh 2019/02/19 23:46:27 Current path is /tmp/busybox 2019/02/19 23:46:27 CmdArray is [/bin/sh] / #
如果出现 pivotRoot error pivot_root invalid argument 的报错,可以先执行 unshare -m 命令,然后使用 rm -rf /tmp/busybox/.pivot_root 命令删除临时文件,再次重试即可。
这里我们使用 it 参数指定以命令行交互的模式启动容器,rootfs 指定准备好的镜像目录。执行完上面的命令后 busybox 容器就成功启动了。 这时候,我们使用 ps 命令查看一下当前进程信息:
/ # /bin/ps -ef PID USER TIME COMMAND 1 root 0:00 /bin/sh 5 root 0:00 /bin/ps -ef
此时,容器内的进程已经与主机完全隔离。 我们再查看一下当前目录下的内容:
/ # pwd / / # /bin/ls -l total 1468 drwxr-xr-x 2 root root 12288 Sep 8 18:09 bin -rw------- 1 root root 1455104 Sep 19 14:47 busybox.tar drwxr-xr-x 4 root root 4096 Sep 19 08:41 dev drwxr-xr-x 3 root root 4096 Sep 19 08:41 etc drwxr-xr-x 2 nobody nobody 4096 Sep 8 18:09 home dr-xr-xr-x 122 root root 0 Sep 19 15:46 proc drwx------ 2 root root 4096 Sep 19 13:07 root drwxr-xr-x 2 root root 4096 Sep 19 08:41 sys drwxrwxrwt 2 root root 4096 Sep 8 18:09 tmp drwxr-xr-x 3 root root 4096 Sep 8 18:09 usr drwxr-xr-x 4 root root 4096 Sep 8 18:09 var
可以看到当前目录已经为根目录,并且根目录下的文件就是我们上面准备的 busybox 镜像文件。 到此,一个完全由我们自己编写的 gocker 已经可以启动容器了。
结语
本课时我们讲解了 Golang 是什么, 并且配置好了 Golang 环境,编译了 gocker,也了解了 Linux /proc 文件系统的一些重要功能,最后使用 gocker 成功启动了一个 busybox 容器。
下一篇我将全面剖析 gocker 的源码以及它的实现原理,到时见。
版权声明:如无特殊说明,文章均为本站原创,版权所有,转载需注明本文链接
本文链接:http://www.bianchengvip.com/article/docker-go/