Todo list

将会更新的文章或着感兴趣的议题

  • aws vpc 子网隔离

  • 容器中的文件

  • k8s crd & operator

  • alertmanager 配置文件与告警使用

  • python sqlalchemy

  • scrum 敏捷开发

  • ECMAScript6 持续更新

  • 浮点型(python/javascript/golang)

  • python 魔术方法

  • helm hooks

  • python import 注意事项

  • rook-ceph-k8s

  • vue相关

  • linux kernal namespace

  • Mvcc


K8S & Jenkins CICD

公司内部各个开发团队,一直有独立运作的习惯,持续集成基本是各自的Jenkins,又由于办公内网,没有足够的硬件资源,搭建ceph这类的分布式存储(我也尝试用几台虚机,搭建了ceph,并测试了存储io,性能感人的差,经费也下不来),所以Jenkins 也一直放在K8S集群外。接下里简单记录一下目前的使用方式

  1. Jenkins添加集群信息:

    image-20201101221351225

  2. 添加用于构建镜像的docker主机,实际上镜像打包还可以通过maven的插件,开发同事在本地开发构建时便是通过maven的docker插件。

    image-20201101221444117

  3. 编写Jenkins的Dockerfile(略,springcloud微服务的话,官方有一个案例,拿来开始改改就可以用了)

  4. 仓库里添加jenkinsfile,在此需要考虑到各种语言的编译过程的包的缓存,用来加速下一次构建编译的速度,以下便是将maven本地仓库的本地路径,挂载到PVC中。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    pipeline {
    agent {
    kubernetes {
    cloud 'k8s-api-cs-software.sunvalley.com.cn'
    nodeSelector 'app=jenkins'
    idleMinutes 5
    yaml """
    apiVersion: v1
    kind: Pod
    metadata:
    labels:
    app: jenkins-jnlp
    spec:
    containers:
    - name: jnlp
    image: harbor.sunvalley.com.cn/library/jenkins-jnlp-slave:3.35-5
    - name: maven
    image: cs-harbor.sunvalley.com.cn/library/maven-base-image:3.0.5
    command:
    - cat
    tty: true
    volumeMounts:
    - mountPath: /data/m2_dev/
    name: m2-dev
    - name: docker-ci
    image: harbor.sunvalley.com.cn/library/docker-ci:v19.03.5
    command:
    - cat
    tty: true
    volumeMounts:
    - mountPath: /var/run/docker.sock
    name: docker-sock
    - mountPath: /data/m2_dev/
    name: m2-dev
    - name: kubectl-tools
    image: harbor.sunvalley.com.cn/library/kubectl-tools:1.16.3
    command:
    - cat
    tty: true
    volumes:
    - name: docker-sock
    hostPath:
    path: /var/run/docker.sock
    - name: m2-dev
    hostPath:
    path: /data/m2_dev/
    """
    // serviceAccountName: admin-sample-user
    }
    }
    stages {
    stage('Run maven') {
    steps {
    // container('maven') {
    // sh 'mvn -B -f pom.xml -s /data/m2_dev/settings.xml clean package -Dmaven.test.skip=true -pl com.sunvalley:mwp-message-center -am -Pdev1 -e -U'
    // }
    // container('docker-ci') {
    // dir(path: "mwp-message-center") {
    // script {
    // docker.withRegistry('https://cs-harbor.sunvalley.com.cn', 'harbor' ){
    // def customImage = docker.build("cs-harbor.sunvalley.com.cn/internal/${env.JOB_NAME}:${env.GIT_COMMIT}")
    // customImage.push()
    // }
    // }
    // }
    // }
    container('kubectl-tools') {
    // sh "sed -i 's/<PROJECT_NAME>/${env.JOB_NAME}/' deployment.yaml"
    // sh "sed -i 's/<BUILD_TAG>/${env.GIT_COMMIT}/' deployment.yaml"
    // sh 'kubectl apply -f deployment.yaml'
    sh "kubectl get pods"
    }
    }
    }
    }
    }
  1. Jenkinsfile 无论时声明式还是脚本式。都不是yaml语法,Jenkins自身提供了一个Linter,不过呀。总是在界面上切来切去。有点麻烦。如果是vscode用户可以用下面的插件,毕竟项目多了,jenkinsfile 熟悉了,这个工作会帮上忙。

    image-20201031090430764

然而,也有需要吐糟的地方,Jenkins的插件管理,管理起来好崩溃。有些插件会依赖另一个插件的高版本。所以升级插件的时候,一并把依赖插件一起升级了。举例就是pipeline的升级,把Jenkins maven插件一并升级了。结果新的Jenkins maven的版本不支持jdk1.6。 老旧的java项目构建时报错。又比如jenkins k8s cloud 的插件的部分功能,在较新的Jenkins上才能运行(也是测试了好久才发现),文档半点没提。甚至试过在升级jenkins插件的是,官方下载中心垮掉了。第二天才恢复。

再吐糟一点,Jenkins的agent,需要回调master的端口来通讯,我们目前是固定了50000端口。在跨公网的场景下,就有点为难了,我不想暴露50000端口到公网啊。

还有呀,Jenkins 的K8S 插件,目前不支持在构建编译过程中, 调用两个K8S集群。描述个案例:我在内网自建的K8S构建后,最后一步再apply到AWS的EKS。(还要花点时间,寻找到优雅的解决方式)


AWS S3 Performance

S3 是AWS的最常用的服务之一,但是对于S3的并发连接数,Amazon S3 宣布提高请求速率性能](https://aws.amazon.com/cn/about-aws/whats-new/2018/07/amazon-s3-announces-increased-request-rate-performance/)

那在大并发的场景下,如何监控S3的性能呢?下面的文章给出了解答。

S3 Best Performance

Your applications can easily achieve thousands of transactions per second in request performance when uploading and retrieving storage from Amazon S3. Amazon S3 automatically scales to high request rates. For example, your application can achieve at least 3,500 PUT/COPY/POST/DELETE or 5,500 GET/HEAD requests per second per prefix in a bucket. There are no limits to the number of prefixes in a bucket. You can increase your read or write performance by parallelizing reads. For example, if you create 10 prefixes in an Amazon S3 bucket to parallelize reads, you could scale your read performance to 55,000 read requests per second.

image-20201028230839926

S3 控制台和都能找到对应的监控指标。Awesome!

额外的小议题:

我一度设想将S3 bucket 挂在到EKS的pods上,作为日志的输出目录,参照文献:利用 S3FS 将 S3 作为共享存储挂载到 Kubernetes Pod。但是此处存在一个问题,是一档pods中的容器重启后,日志文件将会被重新覆盖。

采用S3FS的一写注意事项:

  • 随机写或追加写需要重写整个文件;
  • 由于网络延迟,所以元数据的操作如列出目录等的性能较差;(备注: 在网络存储方案上,如EFS上,也会有同样的问题)
  • 最终一致性会暂时产生中间数据(AMAZON S3数据一致性模型);
  • 没有文件和目录的原子重命名;
  • 安装相同存储桶的多个客户端之间没有协调;
  • 没有硬链接;

vscode pytest

有鬼!!!

在vscode,写一个python脚本的时候,原本应该只往数据库里,插入一条数据。可是有时候执行后,却发现插入了多台数据,并且有时候2条,有时候3条。由于脚本的逻辑不算复杂,于是认为是vscode在搞鬼。反复vscode的setting.json文件后,注释部分配置,之后找到了祸根:文件名以test开始,每次保存的时候,触发了pytest自动执行了一次测试。我又习惯多次ctrl + s,所以就莫名其妙的多了不少数据。


EKS 札记

最近被新规划的中台,忙到焦头烂额。回到EKS话题吧。

  1. 架构和网络的规划。EKS or self-manager K8S,最终投给了EKS,毕竟在我也尝过在AWS 多种部署K8S的方案。

    选择EKS最关键的原因是:EKS 的自带CNI,所有的pods都可以无缝和vpc的EC2,无缝调用。

  2. 在构建EKS的 VPC,我们采用全public子网的模式,放弃了传统私有子网。原因是这个vpc,

  3. EKS的node虽有公网IP,并没有附加弹性网卡,意味着ASG在伸缩后,node可能被重建了。那么在k8s 定义 service资源时,type选择为node type,并不可靠,毕竟node的IP本身就可能在重启后,变更掉。

  4. 其中也有一个小插曲,同事提出来用EKS集群方案,实现网络代理服务应用集群,提供代理IP给爬虫服务。开会中我也脑子热,居然认可了。冷静后,才发现不对劲啊。EKS 的CNI 让每一个pods都能分配到vpc的一个ip地址,但是pods的互联网访问,还是要通过附加在主机的network interface上互联网网关,也就是说通过这个network interface的ip出去呀。简单讲,就是pods 实际还是通过所在ec2的公网IP出去。完全就不是他说的,每个pods 都能搞到一个公网IP,大误啊!

    image-20200710071931788

​ 5. EKS文档中,自带storageclass的例子,通过sc生产


multi EKS in VPC

Hello Chandler,

Thank you for contacting AWS support. My name is Sypher and I will be helping you and your case today. According to your description, I understand you want to ask that is there have any flaws of creating two EKS cluster in one VPC. If I misunderstand your question, please feel free to correct me. Generally speak, there won’t have any flaws if you deploy two EKS clusters in one VPC. The only thing currently it might need to be noticed is the IP address allocate problem. As you might know, Amazon EKS supports native VPC networking via the Amazon VPC Container Network Interface (CNI) plugin for Kubernetes [1]. Using this CNI plugin allows Kubernetes pods to have the same IP address inside the pod as they do on the VPC network. Thus, it means that each pod will allocate one private IP from your VPC. If each EKS cluster might deploy lots of pods in the future, you might need to consider the IP insufficient problem. After I reviewed your EKS Clusters’ VPC, each subnet still have more that 8000 IPs can use. Hence, I think currently there have no issue you need to worry. However, if you have some questions or encountered the issue in the future, please do not hesitate to reach out us again. We are willing to help you solve the problem.

综上,为验证我的疑问:一个VPC,创建多个EKS集群,选择相同的子网,是否会有冲突。因此我动手试了一发。如我推测,AWS的EKS 简直棒呆了!由于EKS的CNI插件,使得PODS的网络接口,对应一个VPC中的一个私有ip(network interface)。这个network interface上的安全组规则,实现了网络的互通。


one cluster or many

在EKS中, 一个集群 OR 多个集群,是一个规划者绕不开的一个问题。我在规划的初期,为每个开发部门(业务独立),创建不同的集群。考虑到集群可能会升级,独立的K8S集群在升级时,关联的业务面也比较可控。

尤其我们额外,帮他们打通了pods cidr与开发办公网段的网络。多个开发团队也都着手将传统部署的应用,容器化,通过K8S作为编排工具。集群的数量以及相应的要求也各有不同。

单一集群,多租户的方式存在多个缺陷:

  • soft multi-tenancy
  • ops affects all tenants
  • same K8S Version

多集群,多租户的方式:

  • Hypervisor for hard multi-tenancy
  • blast Radilis limits
  • diff configs & diff k8s version

ECMAScript 6

菜鸟学ES6

  1. ES6 之模版
1
2
3
4
5
6
7
8
9
10
11
12
13
14
➜ cat aaaa.js   
let name = "koma"

function dd(format){
console.log(format)
}
// dd`4344`
dd(4344)

~/code/algorithm via ⬢ v10.16.0 via algorithm
➜ node aaaa.js
4344

# 这个就是普通的js方法调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
➜ cat aaaa.js 
let name = "koma"

function dd(format,...args){
console.log(format)
console.log(args)
}

dd`你好吖,${name}`%

~/code/algorithm via ⬢ v10.16.0 via algorithm
➜ node aaaa.js
[ '你好吖,', '' ]
[ 'koma' ]
# 这个就是模版调用
# 好笑的是,我在手机屏幕上,看代码时,一度以为js可以不用带括号,就可以调用方法。😓
  1. ES6 之Symbol

    待续。。


EKS Unauthorized
  1. 创建集群,但此次是由同事的IAM账号来创建,创建后的集群,默认只有创建者的可以访问,其他的iam账号(比如我的),就需要额外的做一步
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
[centos@ip-10-100-4-240 ~]$ cat /data/shelley/cluster.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: cs-k8s-cluster
region: us-west-2
version: '1.16'
tags:
'Owner': 'SoftwareDevDept'
vpc:
id: "vpc-05b756b29c94fef66" # (optional, must match VPC ID used for each subnet below)
cidr: "10.100.0.0/16" # (optional, must match CIDR used by the given VPC)
subnets:
# must provide 'private' and/or 'public' subnets by availibility zone as shown
public:
us-west-2a:
id: "subnet-093837539ccacaae8"
cidr: "10.100.0.0/19" # (optional, must match CIDR used by the given subnet)
us-west-2b:
id: "subnet-0b6b35e29c009928a"
cidr: "10.100.32.0/19" # (optional, must match CIDR used by the given subnet)
us-west-2c:
id: "subnet-01e3bfde4755f67e2"
cidr: "10.100.64.0/19" # (optional, must match CIDR used by the given subnet)
us-west-2d:
id: "subnet-0286c131713e85585"
cidr: "10.100.96.0/19" # (optional, must match CIDR used by the given subnet)
private:
us-west-2a:
id: "subnet-0ca641ee980ff32f9"
cidr: "10.100.128.0/19" # (optional, must match CIDR used by the given subnet)
us-west-2b:
id: "subnet-08c29d1387063d44e"
cidr: "10.100.160.0/19" # (optional, must match CIDR used by the given subnet)
us-west-2c:
id: "subnet-09c6c0901fb5237a4"
cidr: "10.100.192.0/19" # (optional, must match CIDR used by the given subnet)
us-west-2d:
id: "subnet-00d5c0082c082cf54"
cidr: "10.100.224.0/19" # (optional, must match CIDR used by the given subnet)

iam:
serviceRoleARN: "arn:aws:iam::211394563914:role/eksServiceRole"
managedNodeGroups:
- name: managed-public
labels: { role: public }
availabilityZones: ["us-west-2a", "us-west-2b", "us-west-2c", "us-west-2d"]
instanceType: t2.medium
minSize: 1
maxSize: 5
desiredCapacity: 1
volumeSize: 100
tags:
'Owner': 'SoftwareDevDept'
'snapshot_days': '7'
ssh:
allow: true
publicKeyName: "Oregon_k8s"
sourceSecurityGroupIds: ["sg-029e90d289e61032a"]
- name: managed-private
labels: { role: private }
availabilityZones: ["us-west-2a", "us-west-2b", "us-west-2c", "us-west-2d"]
instanceType: t2.medium
privateNetworking: true
minSize: 1
maxSize: 10
desiredCapacity: 1
volumeSize: 100
tags:
'Owner': 'SoftwareDevDept'
'snapshot_days': '7'
ssh:
allow: true
publicKeyName: "Oregon_k8s"
sourceSecurityGroupIds: ["sg-029e90d289e61032a"]
cloudWatch:
clusterLogging:
# enable specific types of cluster control plane logs
enableTypes: ["audit", "authenticator", "controllerManager", "api", "scheduler"]
# all supported types: "api", "audit", "authenticator", "controllerManager", "scheduler"
# supported special values: "*" and "all"
[centos@ip-10-100-4-240 ~]$ eksctl create cluster -f cluster.yaml
  1. 按照官方文档,添加自己的用户到system:masters管理员组里。
1
2
3
4
5
6
7
8
9
kubectl edit -n kube-system configmap/aws-auth
添加以下用户信息
apiVersion: v1
data:
mapUsers: |
- userarn: arn:aws:iam::111122223333:user/chandler.guo
username: chandler.guo
groups:
- system:masters

​ 那么此处问题来了,如果我只想给到view的权限呢?由应该如何处理。

  1. 在本地电脑上通过aws client 生成kube config配置。

    aws eks --region us-west-2 update-kubeconfig --name cs-k8s-cluster

  2. 回顾:

    客户端请求EKS API service 时,kubectl 先调用K8S的API时,aws identify 先验证身份,身份验证通过,才会将请求给到EKS集群,EKS中采用原生的RBAC鉴权,再返回到客户端。

    image-20200619094809050

    在此基础上,我又再提出一个疑问


distro for elasticsearch

AWS ES服务的认证,以往我们依赖与iam access key,但是新版本突然发现了一个新世界:Open Distro for Elasticsearch。opendistro官网。并且上开源的,功能描述上,提供认证,还有监控,还有告警。这些功能xpack中也有,当然也是收费的。

image-20200609115746773

角色控制也非常的棒,可配置cluster的权限,索引的权限,租户的权限。分配给普通应用的账号,就不需要cluster里的权限了。

image-20200609120201552

功能可不止这一点,还支持用户认证还支持绑定Active Directory and LDAP。可惜有新项目,只能浅尝而止了。