了解eBPF技术

eBPF 的全称“扩展的伯克利数据包过滤器 (Extended Berkeley Packet Filter)” 来看,它是一种数据包过滤技术,是从 BPF (Berkeley Packet Filter) 技术扩展而来的。

BPF 提供了一种在 内核事件 和 用户程序 事件发生时安全注入代码的机制,这就让非内核开发人员也可以对内核进行控制。随着内核的发展,BPF 逐步从最初的数据包过滤扩展到了网络、内核、安全、跟踪等,而且它的功能特性还在快速发展中,这种扩展后的 BPF 被简称为 eBPF(早期的 BPF 被称为经典 BPF,简称 cBPF)。实际上,现代内核所运行的都是 eBPF,如果没有特殊说明,内核和开源社区中提到的 BPF 等同于 eBPF 。

使用场景及分类

根据 eBPF 的功能和使用场景,主要分类三类:

跟踪

从内核和程序的运行状态中提取跟踪信息,来了解当前系统正在发生什么。

跟踪类 eBPF 程序主要用于从系统中提取跟踪信息,进而为监控、排错、性能优化等提供数据支撑。

其中 BCC 工具集中包含的绝大部分工具也都属于这个类型。

网络

对网络数据包进行过滤和处理,以便了解和控制网络数据包的收发过程。

网络类 eBPF 程序主要用于对网络数据包进行过滤和处理,进而实现网络的观测、过滤、流量控制以及性能优化等各种丰富的功能。根据事件触发位置的不同,网络类 eBPF 程序又可以分为 XDP(eXpress Data Path,高速数据路径)程序、TC(Traffic Control,流量控制)程序、套接字程序以及 cgroup 程序。

如著名的开源项目 cilium ,主要用到了ebpf 中的 XDP (eXpress Data Path,高速数据路径)技术。

安全

第三类是除跟踪和网络之外的其他类型,包括安全控制、BPF 扩展等等。

插桩技术

eBPF支持多种事件源,可以在整个软件栈中提供能见度,其实现目前主要通过两种技术,分别为 动态插桩静态插桩,有时候只用其中一种方式是无法实现我们的需求,这时就需要两者相互配合使用了。

动态插桩: kprobes 和 uprobes

动态插桩方式可以做到在程序运行期间,动态的插入观察点,而软件的运行不会受到任何影响,在这点做到了零开销。

kprobes 一般指内核态级别的函数插桩,而 uprobes 则指用户态级别的函数插桩。

动态插桩技术一般需要在 内核函数应用函数开始位置结束位置进行插桩。例如

#!/usr/local/bin/bpftrace

// this program times vfs_read()

kprobe:vfs_read
{
@start[tid] = nsecs;
}

kretbrobe:vfs_read
/@start[tid]/
{
$duration_us = (nsecs - @start[tid]) / 1000;
@us = hist($duration_us);
delete(@start[tid]));
}

这里kprobe:vfs_read 表示是内核函数bfs_read的起始插桩,而kretbroke:vfs_read则是函数的结果插桩,通过对这两个地方分别插桩就可以计算出当前函数的执行时间。

被插桩的函数在整个软件栈中有成千上万个,所以我们可以在任意关注的地方进行插桩,并编写自己的代码实现想要的功能。

动态插桩技术有一点不好的地方就是随着软件版本的迭代变更,被插桩的函数有可能会被重命名或者被移除,这时候会导致一些BPF工具没有办法直接使用,要想继续使用这些BPF工具只能跟着将其进行调整,这个问题十分令人头疼;除此之外还有一个问题就是编译器可能会将一些函数进行 inline 化,这时候会导致这些函数无法使用 kprobesuprobes 动态插桩。

静态插桩: tracepoint 和 USDT

静态插桩会将一些稳定的事件名字编码到软件代码中,由开发者自行维护。BPF跟踪工具支持内核的静态插桩技术,也支持用户态的静态定义跟踪插桩 USDT(user level statically defined tracing)。

不过静态插桩技术也存在一定的问题,那就是会增加开发者的维护成本,同时静态插桩点数量一般很有限。

所有如果我们要开发 BPF工具的话,一般都推荐优先使用静态插桩技术,如果仍无法满足需求的话,再考虑使用动态插桩技(kprobes 或 uprobes)

开发工具

直接通过BPF指令编写BPF程序是件非常繁琐的一件事,因此出现了一些高级语言支持的BPF前端工具,主流开发工具主要是 BCCbpftrade

bcc、bpftrace 与bpf
bcc、bpftrace 与bpf

BCC

BBC(BPF编译器集合,BPF Compiler Collection) 是最早的开发BPF的开发框架。它提供了一个编写内核BPF程序的C语言环境,同时还提供了其它高级语言如Python、Lua 或 C++环境来实现用户端接口,它也是 libbcclibbpf 库的前身,这两个库提供了使用BPF程序对事件进行观测的库函数。

用户可以直接在系统上 安装BCC 即可,不用手动亲自编码代码就可以直接使用自带的一些工具,这些命令的使用场景及用法请参考官方文档 https://github.com/iovisor/bcc/blob/master/docs/tutorial.md

sudo apt-get install bpfcc-tools linux-headers-$(uname -r)

工具集将安装在 /sbin (/usr/sbin in Ubuntu 18.04) 目录,他们的扩展名为 -bpfcc .

$ ls /sbin | grep bpfcc
argdist-bpfcc
bashreadline-bpfcc
bindsnoop-bpfcc
biolatency-bpfcc
biolatpcts-bpfcc
biosnoop-bpfcc
biotop-bpfcc
bitesize-bpfcc
bpflist-bpfcc
btrfsdist-bpfcc
btrfsslower-bpfcc
cachestat-bpfcc
cachetop-bpfcc
capable-bpfcc
cobjnew-bpfcc
compactsnoop-bpfcc
cpudist-bpfcc
cpuunclaimed-bpfcc
criticalstat-bpfcc
dbslower-bpfcc
dbstat-bpfcc
dcsnoop-bpfcc
dcstat-bpfcc
deadlock-bpfcc
dirtop-bpfcc
drsnoop-bpfcc
execsnoop-bpfcc
exitsnoop-bpfcc
ext4dist-bpfcc
ext4slower-bpfcc
filelife-bpfcc
fileslower-bpfcc
filetop-bpfcc
funccount-bpfcc
funcinterval-bpfcc
funclatency-bpfcc
funcslower-bpfcc
gethostlatency-bpfcc
hardirqs-bpfcc
inject-bpfcc
javacalls-bpfcc
javaflow-bpfcc
javagc-bpfcc
javaobjnew-bpfcc
javastat-bpfcc
javathreads-bpfcc
killsnoop-bpfcc
klockstat-bpfcc
llcstat-bpfcc
mdflush-bpfcc
memleak-bpfcc
mountsnoop-bpfcc
mysqld_qslower-bpfcc
netqtop-bpfcc
nfsdist-bpfcc
nfsslower-bpfcc
nodegc-bpfcc
nodestat-bpfcc
offcputime-bpfcc
offwaketime-bpfcc
oomkill-bpfcc
opensnoop-bpfcc
perlcalls-bpfcc
perlflow-bpfcc
perlstat-bpfcc
phpcalls-bpfcc
phpflow-bpfcc
phpstat-bpfcc
pidpersec-bpfcc
profile-bpfcc
pythoncalls-bpfcc
pythonflow-bpfcc
pythongc-bpfcc
pythonstat-bpfcc
readahead-bpfcc
reset-trace-bpfcc
rubycalls-bpfcc
rubyflow-bpfcc
rubygc-bpfcc
rubyobjnew-bpfcc
rubystat-bpfcc
runqlat-bpfcc
runqlen-bpfcc
runqslower-bpfcc
shmsnoop-bpfcc
slabratetop-bpfcc
sofdsnoop-bpfcc
softirqs-bpfcc
solisten-bpfcc
sslsniff-bpfcc
stackcount-bpfcc
statsnoop-bpfcc
swapin-bpfcc
syncsnoop-bpfcc
syscount-bpfcc
tclcalls-bpfcc
tclflow-bpfcc
tclobjnew-bpfcc
tclstat-bpfcc
tcpaccept-bpfcc
tcpconnect-bpfcc
tcpconnlat-bpfcc
tcpdrop-bpfcc
tcplife-bpfcc
tcpretrans-bpfcc
tcprtt-bpfcc
tcpstates-bpfcc
tcpsubnet-bpfcc
tcpsynbl-bpfcc
tcptop-bpfcc
tcptracer-bpfcc
threadsnoop-bpfcc
tplist-bpfcc
trace-bpfcc
ttysnoop-bpfcc
vfscount-bpfcc
vfsstat-bpfcc
wakeuptime-bpfcc
xfsdist-bpfcc
xfsslower-bpfcc
zfsdist-bpfcc
zfsslower-bpfcc

目前大概有120多个命令,可以直接执行这些命令

sudo opensnoop-bpfcc

相关文档

开发教程 https://github.com/iovisor/bcc/blob/master/docs/tutorial_bcc_python_developer.md
参考指南 https://github.com/iovisor/bcc/blob/master/docs/reference_guide.md

如果要用 BCC 开发其它程序的话,一般是通过  TRACEPOINT_PROBE(category, event)  来定义一个跟踪点处理函数。

对我们要跟踪的短时进程问题来说,也就是下面这两个跟踪点:

// 定义sys_enter_execve跟踪点处理函数.
TRACEPOINT_PROBE(syscalls, sys_enter_execve)
{
    //待添加处理逻辑
}

// 定义sys_exit_execve跟踪点处理函数.
TRACEPOINT_PROBE(syscalls, sys_exit_execve)
{
    //待添加处理逻辑
}

其中 syscalls 是分类,而 sys_enter_execve 是跟踪点。它其实就是下面即将介绍的 bpftrace 中的 tracepoint:syscalls:sys_enter_execve 跟踪点。

bpftrace

bpftrace是一个新兴的前端,其源代码非常简洁,它同样也是基于 libbcclibbpf 库构建的。

bpftrace 原理

bpftrace 会把你开发的脚本借助 BCC 编译加载到内核中执行,再通过 BPF 映射获取执行的结果。

对于 bpftrace 安装很简单

# Ubuntu 19.04
sudo apt-get install -y bpftrace

# RHEL8/CentOS8
sudo dnf install -y bpftrace

安装好 bpftrace 之后,你就可以执行  bpftrace -l  来查询 内核插桩跟踪点

# 查询所有 内核插桩 和 跟踪点
sudo bpftrace -l

# 使用通配符查询所有的系统调用 跟踪点
sudo bpftrace -l 'tracepoint:syscalls:*'

# 使用通配符查询所有名字包含"execve"的跟踪点
sudo bpftrace -l '*execve*'

对于 跟踪点 来说,你还可以加上  -v  参数查询函数的入口参数或返回值。

# 查询execve入口参数格式
$ sudo bpftrace -lv tracepoint:syscalls:sys_enter_execve
tracepoint:syscalls:sys_enter_execve
    int __syscall_nr
    const char * filename
    const char *const * argv
    const char *const * envp

# 查询execve返回值格式
$ sudo bpftrace -lv tracepoint:syscalls:sys_exit_execve
tracepoint:syscalls:sys_exit_execve
    int __syscall_nr
    long ret

而由于内核函数属于不稳定的 API,在 bpftrace 中只能通过  arg0、arg1  这样的参数来访问,具体的参数格式还需要参考内核源代码( https://www.kernel.org/ ),注意内核的版本号差异。

相关文档

bpftrace一行教程 https://github.com/iovisor/bpftrace/blob/master/docs/developers.md
参考指南 https://github.com/iovisor/bpftrace/blob/master/docs/reference_guide.md

对比

BCC 与 bpftrace 两者具有互补性,bpftrace在编写功能强大的单行程序或短小的脚本方便十分理解;BCC则更适合开发大型复杂的脚本和作为后台进程使用,同时它还可以调用其它的库。比如目前很多用Python来开发BCC程序,它们使用Python的 argparse 库来提供复杂的命令行参数运行。

BCC 和 bpftrace 它们并不属于内核代码仓库的项目,而是托管在 Github 上一个名为 IO Visor的Linux基金会。

推荐阅读:https://www.brendangregg.com/ebpf.html

参考资料

k8s解决证书过期问题

在k8s中的时间会提示证书过期问题,如

# kubectl get nodes
Unable to connect to the server: x509: certificate has expired or is not yet valid

这里我们介绍一下续期方法。

注意:当前集群通过 kubeadm 命令创建。

kubeadm 安装得证书默认为 1 年,注意原证书文件必须保留在服务器上才能做延期操作,否则就会重新生成,集群可能无法恢复

准备

这里先查看一下测试集群的证书过期时间

# kubeadm certs check-expiration
[check-expiration] Reading configuration from the cluster...
[check-expiration] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'

CERTIFICATE                EXPIRES                  RESIDUAL TIME   CERTIFICATE AUTHORITY   EXTERNALLY MANAGED
admin.conf                 Aug 30, 2022 03:18 UTC   324d                                    no      
apiserver                  Aug 30, 2022 03:18 UTC   324d            ca                      no      
apiserver-etcd-client      Aug 30, 2022 03:18 UTC   324d            etcd-ca                 no      
apiserver-kubelet-client   Aug 30, 2022 03:18 UTC   324d            ca                      no      
controller-manager.conf    Aug 30, 2022 03:18 UTC   324d                                    no      
etcd-healthcheck-client    Aug 30, 2022 03:18 UTC   324d            etcd-ca                 no      
etcd-peer                  Aug 30, 2022 03:18 UTC   324d            etcd-ca                 no      
etcd-server                Aug 30, 2022 03:18 UTC   324d            etcd-ca                 no      
front-proxy-client         Aug 30, 2022 03:18 UTC   324d            front-proxy-ca          no      
scheduler.conf             Aug 30, 2022 03:18 UTC   324d                                    no      

CERTIFICATE AUTHORITY   EXPIRES                  RESIDUAL TIME   EXTERNALLY MANAGED
ca                      Aug 28, 2031 03:18 UTC   9y              no      
etcd-ca                 Aug 28, 2031 03:18 UTC   9y              no      
front-proxy-ca          Aug 28, 2031 03:18 UTC   9y              no  

可以看到过期时间为 2022-08-30。

Continue reading

istio在虚拟机vm下的安装方法

建议参考官方文档 https://istio.io/latest/zh/docs/setup/install/virtual-machine/ ,这里提醒大家对于命令中文版部分命令与英文版不一致,请以 英文版 为准。

对于istio在vm上的安装教程主要分为三部分。首先是在k8s的master节点生成vm连接主节点的一些配置信息,其实是在vm上应用这些配置信息,最后也就是验证连接是否成功。

本篇主要介绍“单网络”的情况, 对于”多网络“请自行参考官方文档。

vm环境准备

生成vm通讯配置信息

这里主要介绍一些新手迷惑的部分。如环境变量设置及vm注册的方式

设置环境变量

在设置变量时,对于”单网络“来讲 CLUSTER_NETWORK 和 VM_NETWORK 保留空值即可。如我这里设置如下

$ VM_APP="myapp"
$ VM_NAMESPACE="vm"
$ WORK_DIR="/root/myapp"
$ SERVICE_ACCOUNT="vm-sa"
$ CLUSTER_NETWORK=""
$ VM_NETWORK=""
$ CLUSTER="Kubernetes"

每个环境变量的解释:
VM_APP 表示vm上应用的名称
VM_NAMESPACE 表示应用所在的namespace
WORK_DIR 生成vm配置信息保留的目录,任何位置即可
SERVICE_ACCOUNT 服务运行的账号 ,即yaml文件中的 ServiceAccount 字段
CLUSTER 集群名称,默认为 Kubernetes 即可。

Continue reading

利用 docker buildx 构建多平台镜像

什么是 docker buildx

Docker Buildx是一个CLI插件,它扩展了Docker命令,完全支持Moby BuildKit builder toolkit提供的功能。它提供了与docker build相同的用户体验,并提供了许多新功能,如创建作用域生成器实例和针对多个节点并发构建。

Docker Buildx包含在Docker 19.03中,并与以下Docker Desktop版本捆绑在一起。请注意,必须启用“实验特性”选项才能使用Docker Buildx。

Docker Desktop Enterprise version 2.1.0
Docker Desktop Edge version 2.0.4.0 or higher

创建 builder 实例

由于 Docker 默认的 builder 实例不支持同时指定多个 –platform,所有我们必须先创建一个 builder 实例

$ docker buildx create --use --name=mybuilder-cn --driver docker-container

--use 表示使用当前创建的 builder 实例
--name 实例名称
--driver 实例驱动(docker、 docker-container 和 kubernetes)

更多用法通过命令 docker buildx create -h 查看

Continue reading

服务网格Istio之服务入口 ServiceEntry

使用服务入口(Service Entry) 来添加一个服务入口到 Istio 内部维护的服务注册中心。添加了服务入口后,Envoy 代理可以向服务发送流量,就好像它是网格内部的服务一样,可参考 https://istio.io/latest/zh/docs/concepts/traffic-management/#service-entries

简单的理解就是允许内网向外网服务发送流量请求,但你可能会说正常情况下在pod里也是可以访问外网的,这两者有什么区别呢?

确实默认情况下,Istio 配置 Envoy 代理可以将请求传递给外部服务。但是无法使用 Istio 的特性来控制没有在网格中注册的目标流量。这也正是 ServiceEntry 真正发挥的作用,通过配置服务入口允许您管理运行在网格外的服务的流量。

此外,可以配置虚拟服务和目标规则,以更精细的方式控制到服务条目的流量,就像为网格中的其他任何服务配置流量一样。

为了更好的理解这一块的内容,我们先看一下普通POD发送请求的流程图

普通 Pod 请求

Continue reading

在linux下安装Kubernetes

环境 ubuntu18.04 64位

为了解决国内访问一些国外网站慢的问题,本文使用了国内阿里云的镜像。

更换apt包源

这里使用aliyun镜像 https://developer.aliyun.com/mirror/, 为了安全起见,建议备份原来系统默认的 /etc/apt/sources.list 文件

编辑文件 /etc/apt/sources.list,将默认网址 http://archive.ubuntu.com 或 http://cn.archive.ubuntu.com 替换为 http://mirrors.aliyun.com

更新缓存

$ sudo apt-get clean all
$ sudo apt-get update

安装Docker

参考官方文档 https://docs.docker.com/engine/install/ubuntu/ 或 aliyun 文档 https://developer.aliyun.com/mirror/docker-ce

Continue reading

初识kubernetes

对于一个刚刚接触kubernetes(k8s)的新手来说,想好更好的学习它,首先就要对它有一个大概的认知,所以本文我们先以全局观来介绍一个kubernetes。

kubernetes架构

8ee9f2fa987eccb490cfaa91c6484f67
kubernetes 架构图

kubernets整体可以分为两大部分,分别为 MasterNode ,我们一般称其为节点,这两种角色分别对应着控制节点和计算节点,根据我们的经验可以清楚的知道 Master 是控制节点。

Master 节点

控制节点 Master 节点由三部分组成,分别为 Controller ManagerAPI ServerScheduler ,它们相互紧密协作,每个部分负责不同的工作职责。

  • controller-manager 全称为 kube-controler-manager 组件,主要用来负责容器编排。如一个容器(实际上是pod,pod是最基本的调度单元。一般一个pod里会部署一个容器服务)服务可以指定副本数量,如果实际运行的副本数据与期望的不一致,则会自动再启动几个容器副本,最终实现期望的数量。这个组件,就是一系列控制器的集合。我们可以查看一下 Kubernetes 项目的 pkg/controller 目录, 伪代码如下:
for {
  实际状态 := 获取集群中对象X的实际状态(Actual State)
  期望状态 := 获取集群中对象X的期望状态(Desired State)
  if 实际状态 == 期望状态{
    什么都不做
  } else {
    执行编排动作,将实际状态调整为期望状态
  }
}
  • api server 对外提供api服务,用来接收命令进行集群管理。对内负责与etcd注册中心进行通讯,进行一些配置信息的存储与读取
  • scheduler 负责调度。如一个容器存放到k8s集群中的哪个node节点最为合适

实际上这三个节点的功能远远多于我们描述的。

Continue reading

k8s中的Service与Ingress

集群中的服务要想向外提供服务,就不得不提到Service和Ingress。 下面我们就介绍一下两者的区别和关系。

Service

必须了解的一点是 Service 的访问信息在 Kubernetes 集群内是有效的,集群之外是无效的

Service可以看作是一组提供相同服务的Pod对外的访问接口。借助Service,应用可以方便地实现服务发现和负载均衡。对于Service 的工作原理请参考https://time.geekbang.org/column/article/68636

当需要从集群外部访问k8s里的服务的时候,方式有四种:ClusterIP(默认)、NodePortLoadBalancerExternalName

下面我们介绍一下这几种方式的区别

一、ClusterIP

该方式是指通过集群的内部 IP 暴露服务,但此服务只能够在集群内部可以访问,这种方式也是默认的 ServiceType。

我们先看一下最简单的Service定义

apiVersion: v1
kind: Service
metadata:
  name: hostnames
spec:
  selector:
    app: hostnames
  ports:
  - name: default
    protocol: TCP
    port: 80
    targetPort: 9376

这里我使用了 selector 字段来声明这个 Service 只携带了 app=hostnames 标签的 Pod。并且这个 Service 的 80 端口,代理的是 Pod 的 9376 端口。

我们定义一个 Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hostnames
spec:
  selector:
    matchLabels:
      app: hostnames
  replicas: 3
  template:
    metadata:
      labels:
        app: hostnames
    spec:
      containers:
      - name: hostnames
        image: k8s.gcr.io/serve_hostname
        ports:
        - containerPort: 9376
          protocol: TCP

这里我们使用的 webservice 镜像为 k8s.gcr.io/serve_hostname,其主要提供输出当前服务器的 hostname 的功能,这里声明的Pod份数是 3 份,此时如果我们依次访问 curl 10.0.1.175:80 的话,会发现每次响应内容不一样,说明后端请求了不同的 pod 。这是因为 Service 提供的负载均衡方式是 Round Robin

这里的 10.0.1.175 是当前集群的IP,俗称为 VIP,是 Kubernetes 自动为 Service 分配的。对于这种方式称为 ClusterIP 模式的 Service

Continue reading

mac下利用minikube安装Kubernetes环境

本机为mac环境,安装有brew工具,所以为了方便这里直接使用brew来安装minikube工具。同时本机已经安装过VirtualBox虚拟机软件。

minikube是一款专门用来创建k8s 集群的工具。

一、安装minikube

参考 https://kubernetes.io/docs/tasks/tools/install-minikube/, 在安装minkube之前建议先了解一下minikube需要的环境https://kubernetes.io/docs/setup/learning-environment/minikube/

1. 先安装一个虚拟化管理系统,如果还未安装,则在 HyperKit、VirtualBox 或 VMware Fusion 三个中任选一个即可,这里我选择了VirtualBox。

如果你想使用hyperkit的话,可以直接执行 brew install hyperkit 即可。

对于支持的driver_name有效值参考https://kubernetes.io/docs/setup/learning-environment/minikube/#specifying-the-vm-driver, 目前docker尚处于实现阶段。

$ brew install minikube

查看版本号

$ minikube version

minikube version: v1.8.2
commit: eb13446e786c9ef70cb0a9f85a633194e62396a1

安装kubectl命令行工具

$ brew install kubectl

二、启动minikube 创建集群

$ minikube start --driver=virtualbox

如果国内的用户安装时提示失败”VM is unable to access k8s.gcr.io, you may need to configure a proxy or set –image-repository”,
则指定参数–image-repository=registry.cn-hangzhou.aliyuncs.com/google_containers

 $ minikube start --driver=virtualbox --image-repository=registry.cn-hangzhou.aliyuncs.com/google_containers

😄 minikube v1.8.2 on Darwin 10.15.3
✨ Using the virtualbox driver based on existing profile
✅ Using image repository registry.cn-hangzhou.aliyuncs.com/google_containers
💾 Downloading preloaded images tarball for k8s v1.17.3 …
⌛ Reconfiguring existing host …
🏃 Using the running virtualbox “minikube” VM …
🐳 Preparing Kubernetes v1.17.3 on Docker 19.03.6 …
> kubelet.sha256: 65 B / 65 B [————————–] 100.00% ? p/s 0s
> kubeadm.sha256: 65 B / 65 B [————————–] 100.00% ? p/s 0s
> kubectl.sha256: 65 B / 65 B [————————–] 100.00% ? p/s 0s
> kubeadm: 37.52 MiB / 37.52 MiB [—————] 100.00% 1.01 MiB p/s 37s
> kubelet: 106.42 MiB / 106.42 MiB [————-] 100.00% 2.65 MiB p/s 40s
> kubectl: 41.48 MiB / 41.48 MiB [—————] 100.00% 1.06 MiB p/s 40s
🚀 Launching Kubernetes …
🌟 Enabling addons: default-storageclass, storage-provisioner
🏄 Done! kubectl is now configured to use “minikube”

另外在minikube start 有一个选项是–image-mirror-country=’cn’  这个选项是专门为中国准备的,还有参数–iso-url,官方文档中已经提供了阿里云的地址……… 这个选项会让你使用阿里云的镜像仓库,我这里直接指定了镜像地址。

对于大部分国内无法访问到的镜像k8s.gcr.io域名下的镜像都可以在http://registry.cn-hangzhou.aliyuncs.com/google_containers 找到。

Continue reading