Happy Coding, Happy Life

[Serverless 101] - 初识Serverless

| Comments

2019年3月,伯克利的一篇论文《A Berkeley View on Serveless Computing》,预测了Serverless对未来10年云计算的影响;

2019年12月,AWS REInvent上发布了诸多Serverless相关的更新,反响热烈。

Serverless无疑已经成为学术界和工业界关注的焦点。

本文主要聊聊个人对Serverless的一些理解。

读书笔记 - 《金字塔原理》

| Comments

这是一本关于提升逻辑思维能力的大作,也是有效提高写作和演讲水平的红宝书,

趁这几天宅在家里,前细后粗的读了一遍。(后面的太啰嗦,选择性放弃)

k8s之Deployment

| Comments

之前我们了解了如何打包,作为Pod中的容器运行,使用临时或者永久存储机制,设置配置项,接下来我们探讨如何部署和升级。

应用更新的方式

假定在K8S中存在这样的应用: * Service * 3个Pod * 使用ReplicaSet * Clients

初始情况,运行V1版本的应用。接下来,我们希望生成V2版本的镜像,并使用V2版本的Pod/容器进行升级。 存在两种方式: * 先删除V1版本的应用,然后部署V2版本。 * 先新增V2版本的应用,然后删除V1版本。(对于V2版本的新增,可以选择 一次新增全部数量多次新增,每次部分数量

对于第一种方式:简单,但是存在部署的停机时间
对于第二种方式:系统需要同时处理两个版本的应用,尤其是数据Schema需要兼容新旧两个版本

ttt

K8s之configmap

| Comments

几乎所有的应用程序都需要配置(实例的配置信息,外部系统的访问信息等),而这些配置显然不应该被打包到应用程序本身中。

本篇文章看看如何在Kubernetes中配置应用程序的信息。

1.配置容器应用的方式

  • 命令行 最简单的应用配置方式,是使用命令行。

  • 配置文件

随着配置信息增多,考虑到维护成本,可以将配置信息存储到配置文件中。但对于容器而言,使用配置文件的方式需要将配置项打包到镜像中,而且每次配置信息的变更都会导致重新生成镜像,重新部署,维护和变更成本较高。

  • 环境变量

在容器应用中,使用环境变量来实现配置,也是较普遍的一种做法,通过将参数传递给容器中的应用,变更容器运行期的配置信息,如MySQL官方的镜像就使用环境变量MYSQL_ROOT_PASSWORD 来修改超级用户root的密码。

  • volume

另外,基于volume的方式获取配置信息也是一种可行的方式,如使用Git Repo存储配置信息,能有效的做到版本化管理会随时回退。

在K8S中,存储配置信息的资源被称ConfigMap,本部分将介绍ConfigMap、Secret的使用。

2.从命令行传递参数

在Docker容器中,通常使用如下方式传递参数:

  • 使用ENTRYPOINT定义可执行命令
  • 使用CMD传递参数

在ENTRYPOINT中,可以使用如下两种方式启动应用:

  • Shell方式,如ENTRYPOINT node app.js
  • exec方式,如ENTRYPOINT ["node", "app.js"]

注意: 这两种方式的区别在于前者是先启动Shell,由Shell调用node,而后者直接启动node应用。

在K8S中,可以通过配置文件中的commandargs来设置容器中的ENTRYPOINTCMD 譬如

1
2
3
4
5
6
kind: Pod
spec:
  containers:
  - image: some/image
    command: ["/bin/command"]
    args: ["arg1", "arg2", "arg3"]

它们之间的区别如下图所示:

Docker Kubernetes 描述
ENTRYPOINT command 在容器中执行命令
CMD args 给命令传递参数

3.使用环境变量

在K8S中,使用env设置镜像中定义的环境变量。 譬如,容器中存在如下脚本,其中的INTERVAL使用环境变量进行设置:

1
2
3
4
5
6
#!/bin/bash
while :
do
  echo $(date)
  sleep $INTERVAL
done

在K8S中,其配置文件类似如下:

1
2
3
4
5
6
7
8
kind: Pod
spec:
 containers:
 - image: xxxxx
   env:
   - name: INTERVAL
     value: "30"
...

4.使用CONFIGMAP解耦配置

Kubernetes允许将配置项分离到一个称为ConfigMap的单独对象中,它包含若干键/值对,并且值的范围可以从文本到整个配置文件。

应用程序不需要直接读取ConfigMap,甚至不需要知道它的存在。Map的内容可以作为环境变量或者卷传递给容器。

使用kubectl创建ConfigMap的过程中,可以指定多样化的配置机制,类似如下所示:

1
2
3
4
5
$ kubectl create configmap my-config
  --from-file=foo.json                     //导入JSON文件
  --from-file=bar=foobar.conf              //导入配置文件
  --from-file=config-opts/                 //导入目录
  --from-literal=some=thing                //导入文本配置
4.1 使用ConfigMap Entry设置环境变量的值

接下来, 在如上环境变量的例子中,我们使用ConfigMap配置环境变量$INTERVAL的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: v1
kind: Pod
metadata:
  name: env-from-configmap
spec:
  containers:
  - image: xxxx
    env:
    - name: INTERVAL                 //环境变量名
      valueFrom:
        configMapKeyRef:             //使用ConfigMap
          name: fortune-config       //ConfigMap的名称
          key: sleep-interval        //ConfigMap的key
...

在如上的例子中,读取ConfigMapfortune-config中Keysleep-interval对应的值,作为$INTERVAL的值。

4.2 使用ConfigMap Entry作为环境变量

譬如有个ConfigMap,它有两个键,分别是foo、bar。您可以使用envFrom属性将它们全部公开为环境变量,而不是像在前面的示例中那样依次使用env。

如下所示:

1
2
3
4
5
6
7
8
spec:
  containers:
  - image: some-image
    envFrom:                      //使用envFrom代替Env
    - prefix: CONFIG_             //使用前缀
      configMapRef:               //引用ConfigMap
        name: my-config-map
...

CONFIG_作为前缀,将导出如下环境变量CONFIG_foo和CONFIG_bar。当然,前缀是可选的,如不设置,则容器中的环境变量为foo和bar。

4.3 使用ConfigMap Entry作为命令行参数

接下来,让我们看看如何将ConfigMap中的值作为参数传递给容器中运行的进程。我们不能在pod.spec.containers.args字段中直接引用ConfigMap,但是可以从ConfigMap中初始化一个环境变量,然后引用参数中的值,相关代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apiVersion: v1
kind: Pod
metadata:
  name: fortune-args-from-configmap
spec:
  containers:
  - image: xxxxx
    env:
    - name: INTERVAL
      valueFrom:
        configMapKeyRef:
          name: fortune-config
          key: sleep-interval
    args: ["$(INTERVAL)"]
...

其关系如图所示:

4.3 使用ConfigMap volume导出ConfigMap的Entry

ConfigMap除了可以作为环境变量以及命令行参数外,还可以包括整个目录中的配置文件。

譬如,在configmap-files目录下存在如下2个文件:

  • my-nginx-config.conf
1
2
3
4
5
6
7
8
9
10
11
12
server {
  listen              80;
  server_name         www.kubia-example.com;

  gzip on;                                       1
  gzip_types text/plain application/xml;         1

  location / {
    root   /usr/share/nginx/html;
    index  index.html index.htm;
  }
}
  • sleep-interval.txt
1
25

接下来,使用命令创建ConfigMap

1
$ kubectl create configmap fortune-config --from-file=configmap-files

然后,我们可以使用volume将ConfigMap中的内容暴露给容器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: v1
kind: Pod
metadata:
  name: fortune-configmap-volume
spec:
  containers:
  - image: nginx:alpine
    name: web-server
    volumeMounts:
    ...
    - name: config
      mountPath: /etc/nginx/conf.d      //挂载到Pod中的目录
      readOnly: true
    ...
  volumes:
  ...
  - name: config
    configMap:                          //使用configMap作为volume的内容
      name: fortune-config
  ...

K8s之Volume

| Comments

本篇文章主要介绍在K8S中,pod的容器如何访问外部磁盘存储,以及容器间如何实现共享存储,主要内容包括

  • 通过volume和emptyDir在容器中共享数据
  • 在Pod中使用Git Repo
  • 使用外部存储,如GCE
  • 使用PV(PersistentVolume)和PVC(PersistentVolumeClaim)

K8s之Service

| Comments

如何访问Pod?

在非k8s世界中,管理员可以通过在配置文件中指定IP地址或主机名,容许客户端访问,但在k8s中这种方式是行不通的。因为Pod 是有生命周期的,它们可以被创建或销毁。虽然通过 ReplicationController 能够动态地创建Pod,但当Pod被分配到某个节点时,K8s都会为其分配一个IP地址,而该IP地址不总是稳定可依赖的。因此,在 Kubernetes 集群中,如果一组 Pod(称为 backend)为其它 Pod (称为 frontend)提供服务,那么那些 frontend 该如何发现,并连接到这组backend的Pod呢?

K8s之控制器

| Comments

Kubernetes中内建了很多controller(控制器),这些相当于一个状态机,用来控制Pod的具体状态和行为。

K8s之Pod

| Comments

Pod是kubernetes中你可以创建和部署的最小也是最简的单位。Pod代表着集群中运行的进程。Pod中封装着应用的容器(1或多个容器)、存储、独立的网络IP,并管理着容器运行的策略选项。