Spike 回顾

起因

在当前的项目已经快一年了,当初团队成员的一句要求,给大家换来了定期的Innovation Week。在这一周里可以不用专注于当前手上乱七八糟的各种问题和令人有喜有忧的新功能,而是专注于另一项自己感兴趣的小工具、特定使用场景,也可以是某个疑难杂症。而在一周结束之后,团队成员汇聚一堂做简单的成果分享,然后结束这个过程。所以我们的做法本质上还不是Spike,但相互之间却有很多值得借鉴的地方。

这样做的好处显而易见,给成员留足了时间去学习新工具、新技术,也可以看作是一种变向的自我学习周期。当然,从管理者角度出发,无疑燃烧了经费成本,但却不一定对项目有明显的效果。偶然之后才意思到这个Spike的过程是个专业术语,前人早就有了较好的模式和实践流程,而自身尽然摸爬滚打野路子出家弄了半年。好在回过头来看,并没有走 太多的错路,弄出一些奇怪的实践。但却是时候回顾这个Spike原本的样子,然后理解它,免得日后张冠李戴。

什么是Spike?

Spike 常见的英文翻译是“长钉或者刺穿”,作为名词,也可以作为动词。 Spike 一词来源于攀岩中的比喻, 在攀岩过程中,攀岩的人在没有办法落脚的情况下选择使用岩钉作为锚点来保护自己,从而避免跌倒或协助后续的辅助攀登。其次,这个词来源于 Extreme Programming (XP)

而这个词在软件开发中来源于 Extreme Programming

“A spike solution is a very simple program to explore potential solutions.”

来到敏捷开发过程中,由于敏捷中强调不确定性、拥抱变化,那么在日常开发过程中,也会遇到一些任务。比如技术方案或者未知的探索,于是敏捷中的 Spike 是一项技术调研。通过简答的调查、设计、demo 来快速验证,这样说起来和 POC(prove of concept) 是不是很像。

特殊的 “Spike”:起源于客户一次偶然提出的建议,希望在完成项目要求的任务同时,能够有一些自由一些的时间去完成自己感兴趣的技术主题的研究,来提高自身的能力。所以我们把那一小段时间也看成是 Innovation Week,用于去探索新的、未曾使用过的技术。但我们一直用 “Spike” 来描述这样的事情,似乎也解释得通。

较之于 Extreme Programming(极限编程)中的解释最大的不同,我个人认为是对开发人员的自由度。毕竟前者是项目中存在的不确定性和问题亟待解决,而后者 让开发人员有较大的自由度去选择一个新的技术主题进行任意的探索。

为什么要做Spike?

对于极限编程中的 Spike,虽然 Spike 本身没有完成相应的功能,没有交付业务功能,但是为后续可能遇到的难题扫除了障碍、降低了不确定性,从而保障最终业务价值的交付、减少延期的风险,好处已经人人皆知了。

而对亲历的项目中的 “Spike” 而言,从个人角度而非项目的角度有以下几个优点:

  • 激励个人创新,大胆尝试
  • 学习新的技术栈,提升个人能力,拓宽视野
  • 作为紧张的迭代中的一个缓冲期,得以缓和情绪和整理心情

Spike与故事卡的区别?

Spike 在某种程度上可以是一种特殊的user story,区别在于用户故事交付产品业务功能,需求目标相对明确;二spike本身不交付产品功能,问题明确,但在实际做的过程中可能有很多的不确定性。

如何来做Spike?

已经“巧立名目”了,那么接下来就是大展身手,做出点小小的成果的时候了。

第一步: 选定主题

可以是你已经了解的技术栈,但是没有深入研究的某一部分;

也可以是你从其他项目偶然听到的新名词,但是你从来没有实际上手接触过;

另外,如果你想“讨好”项目,那么从技术债中选择一块硬骨头也是一个不错的选择;

亦或是未雨绸缪,率先走入即将被项目采用的新技术中去“探探路”,为项目减少一些隐藏的风险;

如果实在没有头绪,不妨翻阅往期的技术雷达(都是大佬们已经帮你筛选过了的技术条目,又新又好);

或者交给网络,用搜索引擎搜一下类似的关键字 Top 10 New Technology Trends for 2023。

第二步: 初步了解

万般开头难,进入这一步也是真正的开始研究了。既然手中掌握着最关键的线索了,那么以下几个搜索资料的渠道不妨试试:

  • 官方网站 (历史起源、安装/使用方法、功能模块、Roadmap 等等
  • Github 源码 (查看它的开发语言进一步了解特性,Star数量,Issue数量和常见问题
  • 论坛 (避坑指南,踩坑大全,也许有一些最佳实践)
  • Youtube 上的大会视频 (看看视频,听听作者或布道师的理解)
第三步:罗列大纲

为了避免漫无目的,在进行了初步的之后相信你应该大概知道自己想要做些什么,可以在有限的时间内完成哪些任务了。那么把他们按优先级罗列出来或许能时刻提醒自己,也是帮助进一步缩小范围。用一些简要的关键字描述即可,毕竟咱们可是“新手”。

第四步:总结归纳

完成了大部分的任务也别忘了留一点时间,做一下简单的回顾,反思在哪些地方浪费了时间以及踩过的坑,某个问题是否值得关注;或者对比自己用过的同类型工具做一个快速的优劣势分析。

第五步:展示成果

以上如果通通做完了,那么不妨把你的成果和发现给团队成员展示一下,也可以适当邀请其他小组对该主题感兴趣的同学。当然如果能够邀请到客户或者 PO 莅临效果更加,别忘了做一个稍微美观一些的 PPT 。或许有一些意想不到的问题出现,也会有经验丰富的同学给予一些好的建议,帮助我们下次考虑得更周到,做得更好。

回顾一下

在适当的时间开启 Innovation Week,并鼓励团队成员大胆自由地尝试新技术栈和工具,起初或许非常的新鲜。但这一过程也不是总是一帆风顺的,可能灵感枯竭找不到合适的主题,可能忙活了3-5天也没能产出一个好的成功的Demo,又或者辛苦做出来的成果不完全被他人认可…

spike


Reference:

Helm 使用小结

1.What is Helm

Helm is a tool for managing Kubernetes packages called charts.

Three important concepts

  • The Chart is a bundle of information necessary to create an instance of a Kubernetes application.
  • A Release is a running instance of a chart, combined with a specific config.
  • Repository – Publicly available charts.

Helm v2 和 v3的架构如下,主要区别是 Tiller。

helm_arch.png

当然 helm v2与 v3 在命令上也有一些区别,不过老的命令(例如fetch)亲自试验过还能用

Command Helm2 Helm3
Initialize Helm client/server init
Download a chart to your local directory fetch pull
Given a release name, delete the release from Kubernetes delete uninstall
Helm client environment information env
Displays the location of HELM_HOME home
Inspect a chart inspect show
Uninstalls Tiller from a cluster reset

Hub - > repo -> Chart -> App, 从左到右均是一对多的关系。

2.一些常用的命令

关于repo

list repos

helm repo list

add a repo

helm repo add aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts

remove a repo, then check again

helm repo remove aliyun && helm repo list

helm search hub – Searches through the Artifact Hub from dozens of repositories.

helm search hub wordpress

helm search repo – Searches through repositories added in the local helm client using helm repo add.

helm search repo wordpress

When you find a suitable chart, install it using helm install

一个repo里可以有多个chart,

关于chart

download a chart to local

helm pull csi-secrets-store-provider-azure/csi-secrets-store-provider-azure --version 0.0.19 --untar

list all the charts in a repository

helm search repo bitnami

helm repo add stable https://charts.helm.sh/stable

helm show readme stable/ghost

helm install --values=ghost-values.yaml stable/ghost --generate-name

helm ls

helm delete ghost-1622450894

What else

helm upgrade --values=ghost-values.yaml ghost-1576075187 stable/ghost

rollback the app to a specific version

helm rollback ghost-1576075187 1

helm uninstall ghost-1576075187

check all resources which is deployed with helm

helm get manifest datadog -n datadog


Reference:

Clean up Azure Container Registry

起因

打开项目上用了2-3年的Azure Container Registry,就像打开了一个尘封多年的仓库一般。使用者不停的往仓库里堆放物品,但从来不整理、打扫。仓库的容积足够大,不考虑成本的话,都不是问题。但本着“清道夫”的理念,本着清楚潜在问题的出发点(其实是不想后面打开仓库的人也口出“狂言”,而来责怪前面维护的人。)

方法

在个人电脑上,下载镜像过多且长期不删除也会面临磁盘不足的风险。或多或少都适用过类似 docker image rm的命令,但一个一个的清理难免麻烦耗时。这时候就需要一个一键搞定的命令,例如docker system prune

对于Azure Container Registry 这样一个成熟的产品服务,已经不建议个人去造轮子、写脚本了。搜索一番之后找到了一篇不错的文章,里面提到了两个具体的方法。

  • 1.Set a retention policy for untagged manifests (Microsoft Docs)
  • 2.Automatically purge images from an Azure Container Registry (Microsoft Docs)

具体的使用当然还是参照azure官方的文档为宜,毕竟具体实践因情况而异。

对于,需要注意一点,该policy并不能立刻对现有的镜像生效,原文描述如下:

! Important

The retention policy applies only to untagged manifests with timestamps after the policy is enabled. Untagged manifests in the registry with earlier timestamps aren’t subject to the policy. For other options to delete image data, see examples in Delete container images in Azure Container Registry.

运行了一些命令:

1
2
3
4
# 删除2021-04-01 之前的镜像, 有dry-run参数也可以提前测试一下
az acr repository show-manifests --name <YourACRName> --repository demo-web-app \
--orderby time_asc --query "[?timestamp < '2021-04-01'].digest" -o tsv \
| xargs -I% az acr repository delete --name <YourACRName> --image demo-web-app@% --yes
1
2
3
4
5
6
7
8
# 设置定时任务,以后就会自动按照时间来删除
PURGE_CMD="acr purge --filter 'service-one:.*' --ago 180d"

az acr task create --name purgeAppOneImage \
--cmd "$PURGE_CMD" \
--schedule "0 0 * * 2" \
--registry <YourACRName> \
--context /dev/null

意外收获

tag or digest

  • The “digest” is a hash of the manifest, introduced in Docker registry v2.
  • The image ID is a hash of the local image JSON configuration.

在使用 Dockerfile 构建镜像时,base image的使用也涉及这点。提出了一个解决方案 docker-lock ,有兴趣的可以使用看看,欢迎交流心得体会~

Link: https://developers.redhat.com/blog/2020/03/24/red-hat-universal-base-images-for-docker-users#

As you discovered, with docker, tags are mutable. This means that an update to a base image could be pushed that breaks your application code, even if you did not change any of your application code.

You could eliminate this class of bugs by referencing base images by digest rather than by tag. For instance, instead of ruby:2.6.3, use ruby:2.6.3@sha256:2afcffd1a8276d58ef7d2c6d440c83290831abc2d80772a7af720db9aca9cd2e. If you reference by digest, when a new update is pushed to ruby:2.6.3, your application will still use the base image referenced by the digest, and you won’t be affected by the update.

Specifying digests manually is a pain for a variety of reasons. Instead, consider using docker-lock https://github.com/michaelp.... docker-lock is a cli-plugin for docker that manages digests in a lockfile (think package-lock.json), so you can still reference base images by tag but receive the benefits of referencing them by digest.

docker-lock ships with 3 commands that take you from development to production:
docker lock generate finds base images in your docker and docker-compose files and generates a lockfile containing digests that correspond to their tags.
docker lock verify lets you know if there are more recent digests than those last recorded in the lockfile.
docker lock rewrite rewrites Dockerfiles and docker-compose files to include digests.

using-container-image-digests-in-kubernetes-manifests

https://cloud.google.com/architecture/using-container-image-digests-in-kubernetes-manifests)

Tag Count =? Mainfest Count

详解可见文章


Reference:

Bash-对变量动手脚

才疏学浅,最近才注意到变量操作中的一些用法,也由此找到了一个好网站

Operations on variables

  • 1.Length of a variable(获取变量长度)
  • 2.Transformations of variables (变换变量)
  • 3.Removing substrings (删除变量中的子串)
  • 4.Replacing parts of variable names (替换变量中的一部分)

其中的第2点的写法尤其的惊艳到我,非常的简洁但有效,供上网站上的代码帮助理解一下。

1
2
3
4
5
6
7
8
9
10
11
12
~ echo ${TEST:-test}
test

~ echo $TEST

~ export TEST=a_string

~ echo ${TEST:-test}
a_string

~ echo ${TEST2:-$TEST}
a_string

第二次学习英语

背景

最近工作中的项目需要与国外的沟通,英语无可厚非的成为彼此能听懂的通用语言。这也是自学生生涯之后难道认识到英语的重要性的时刻之一。听说读写这四门功课一起上阵,起初让人多少有些“畏惧”。但好在有了一个讲英语的环境后,逼迫自己去学习和练习,也有明显的但效果不是很大的提升。

也侧面验证了学生时代英语学习的局限性,就自身而言,起初的确可以开口,但讲的内容可能自己都不知所云。而读写方面,因为可以借助外部工具来辅助,其实效性也没有那么强,留给大脑思考的时间尚且充足,一般没有太大的问题,但懂行的人也可以一眼看出这段英文背后的人的能力如何。(因为一些用法并不简介,或者乱用介词……)

有哪些方面需要思考:

词汇量、发音&口音、不用总要一种表达方式或固定词组、找到自己的兴趣切入点去学习英语(比如通过喜好的歌英歌曲、电影台词等)、固定场景用语(比如我的工作中:站会、Code Review、Retro…)

我的学习资源

书籍类

podcast类

https://teacherluke.co.uk/ 博主口音非常地道,发音清晰

https://english.stackexchange.com/ 类似https://stackoverflow.com/的风格、模式

https://www.englishclass101.com/ 邮箱注册,领取一些免费的课程

這5個初級英文會話課程可幫您更有自信地說英語

youtube博主

Small talk,开会前经常需要等人,而在这短暂的几分钟里如何双方都没有话题就显得有点儿尴尬。聊一些日常的话题不仅可以帮助增加双方的了解,也可以提升好感,找到一些共同的兴趣爱好。

https://www.youtube.com/watch?v=WGoIoDuf83o

超多形容词,歌曲点评,https://www.youtube.com/watch?v=21lcqYBJQLQ&ab_channel=%E4%B8%8D%E6%98%AF%E6%9F%AF%E6%A1%91%E5%BE%B7

一些实用的网站

  1. BBC的今日短语 (主要是一些地道的短语,俚语)
  2. phrasemix的english lessons (场景用语,用英语讲解固定场景下的对话,实用型)

我的git常用命令

快速查看最近的commit id,commit message
git log --oneline

回到某个commit版本
git reset --hard <commit id>

查看所有分支,包含本地的和远程的
git branch -a

查看所有tag
git tag

Mongodb 的一些概念

基本概念,还是对照常用的关系型数据库,这样更容易理解一些

6V7h3n.png

collection

mongodb是通过一个个collection来做数据存储的,可以类比关系型数据库的表。

shard_key (分片键)

mongodb是通过分片键来对collection进行分区的,也就是通过分片键来决定一个document如何分布式存入collection中。分片键是每个存放在collection中的document都持续拥有的不可缺少的一个字段或多个字段的组合。 分片键有下面几个要求:

  • 每个document都必须拥有,不可缺少。
  • 已经分片的数据,分片键不可更改。
  • 分片键必须加上索引。
  • 分片键的选择对分片的性能、效率和可扩展性都有着重要影响。分片键和索引也会影响集群的分片策略。

分片键索引

分片键必须有索引,索引可以是分片键上的索引,当分片键是索引前缀时,也可以是复合索引。 注意:分片键索引必须是横向(正向),比如用id做索引时定义为key{id:1} 参考:https://docs.mongodb.com/manual/core/sharding-shard-key/#sharding-shard-key-indexes

shard key在sharding搭建完毕后是不能修改的,一个collection上只能有一个shard key。
shard key上必须有索引(可以是以shard key开头的联合索引),如果没有mongodb会为shard key创建索引。如果是已经存在的collection那么必须手动为shard key创建索引。

MongoDB creates a unique index on the _id field during the creation of a collection. The _id index prevents clients from inserting two documents with the same value for the _id field. You cannot drop this index on the _id field.

mongodb offical doc https://docs.mongodb.com/manual/indexes/

Openshift E04 Image Stream是个啥

Image Stream(中文名 镜像流) 是一组镜像的集合, OpenShift默认情况下提供了几个Image Streams,包括许多流行的runtime和frameworks。

Image Streams tag(中文名 镜像流标签对象)是指向Image Streams中的image的别名。通常缩写为istag。它包含一个image历史记录,表示为tag曾经指向的所有images的堆栈。

(??? image stream就是类似repo的概念)

一个镜像流标签对象(ImageStreamTag)指向一个镜像,可以是本地镜像或者远程镜像。如下的名为“python”的镜像流包含两个标签,标签34指向Python v3.4镜像,标签35指向Pythonv3.5镜像。

导入Image Stream

1
2
3
4
5
# Method 1
oc create -f xxx.yaml -n openshift

# Method 2
oc import-image

查看Image Stream
oc get is -n openshift

查看Image Stream Tag

oc get istag

例子

1
2
3
4
5
docker pull ericnie2017/s2i-tomcat:latest

oc import-image ericnie2017/s2i-tomcat -n openshift --confirm --insecure

oc get is -n openshift | grep tomcat

Service Catalog 中看到的不能与 oc get is 的结果一一对应,只能部分对应。

知乎-Service Catalog及OpenShift的历史

Openshift E03 谈谈S2I

关于OpenShift,至今为止还没有梳理核心组件和概念上的解释,但似乎并不太妨碍初步的简单使用。而 Source to Image(S2I) 是OpenShift 的一个重要功能,也是其的一大特色。

What

第一:从OpenShift的角度来看

Source to Image(S2I) 是OopenShift中应用容器化的 标准流程

第二: 从自身工具的属性来看

Source-to-Image (S2I) 是一种用于构建可重复生成的 Docker 格式容器镜像的工具。

How

S2I 需要的最基本的输入只有两个: 一个是源代码仓库(Source Code);另一个是Builder Image(也称“构建镜像、Builder镜像”、基础镜像、构建器)

从应用的源代码构建并部署,Openshift通过一个S2I的构建过程编译打包并实现发布,具体可以参考这篇文章

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# install s2i tool on MacOS
brew install source-to-image

# s2i create <image name> <destination directory>
s2i create s2i-tomcat s2i-tomcat

# get dir ,file
➜ s2i-tomcat tree
.
├── Dockerfile
├── Makefile
├── README.md
├── s2i
│ └── bin
│ ├── assemble
│ ├── run
│ ├── save-artifacts
│ └── usage
└── test
├── run
└── test-app
└── index.html

4 directories, 9 files

S2I tomcat 镜像定制案例,源码可见 https://github.com/cicd-draft/s2i-tomcat

OpenShift的构建

OpenShift支持4种构建方式:Docker构建、S2I构建、Pipeline构建和自定义构建。详情可见官方说明

  • Docker构建会调用docker build命令,基于所提供的Dockerfile文件和所提供的内容来构建Docker镜像。

  • S2I构建是OpenShift的原创,它根据指定的构建镜像(Builder Image)和源代码(Source Code),构建生成可部署Docker镜像,并推送到OpenShift内部集成镜像库中。

  • Pipeline构建方式允许开发者定义Jenkins Pipeline。在项目首次使用该构建方式时,OpenShift容器云平台会启动一个Jenkins服务,然后再将该Pipeline交由它来执行,并负责启动、监控和管理该构建。BuildConfig对象中可以直接包含Jenkins Pipeline的内容,或者包含其Git仓库地址。


Openshift E02 部署Jenkins服务

OpenShift 项目默认提供了两个Jenkins部署模板, Jenkins-ephemeral 和 Jenkins-persistent

  • Jenkins-ephemeral 模板部署的Jenkins服务的数据在容器退出后将丢失,适合测试使用;

  • Jenkins-persistent 模板部署需要持久化卷的支持,其部署的Jenkins 服务的数据可以被持久化。

这里有很多官方的案例源码: https://github.com/openshift/origin/tree/v1.3.0/examples

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
oc login -u developer https://192.168.99.109:8443

# create a new project, name: ci
oc new-project ci

# Create a template,
oc create -f https://raw.githubusercontent.com/openshift/origin/v1.3.0/examples/jenkins/jenkins-ephemeral-template.json

# Get template
oc get template
NAME DESCRIPTION PARAMETERS OBJECTS
jenkins-ephemeral Jenkins service, without persistent storage.... 6 (1 generated) 6

#
➜ ~ oc policy add-role-to-user edit -z default
role "edit" added: "default"

#
➜ ~ oc new-app --template=jenkins-ephemeral --param=JENKINS_PASSWORD=welcome123
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
--> Deploying template "ci/jenkins-ephemeral" to project ci

jenkins-ephemeral
---------
Jenkins service, without persistent storage.
WARNING: Any data stored will be lost upon pod destruction. Only use this template for testing

A Jenkins service has been created in your project. The username/password are admin/welcome. The tutorial at https://github.com/openshift/origin/blob/master/examples/jenkins/README.md contains more information about using this template.

* With parameters:
* Jenkins Service Name=jenkins
* Jenkins JNLP Service Name=jenkins-jnlp
* Jenkins Password=welcome
* Memory Limit=512Mi
* Jenkins ImageStream Namespace=openshift
* Jenkins ImageStreamTag=jenkins:latest

--> Creating resources ...
route.route.openshift.io "jenkins" created
deploymentconfig.apps.openshift.io "jenkins" created
serviceaccount "jenkins" created
rolebinding.authorization.openshift.io "jenkins_edit" created
service "jenkins-jnlp" created
service "jenkins" created
--> Success
Access your application via route 'jenkins-ci.192.168.99.109.nip.io'
Run 'oc status' to view your app.

部署失败了,💔

1
2
3
4
5
6
7
oc delete all -l app=jenkins-ephemeral
pod "jenkins-1-6k7s6" deleted
replicationcontroller "jenkins-1" deleted
service "jenkins" deleted
service "jenkins-jnlp" deleted
deploymentconfig.apps.openshift.io "jenkins" deleted
route.route.openshift.io "jenkins" deleted

不能删除 serviceaccounts

1
2
oc delete serviceaccounts -l app=jenkins-ephemeral
oc delete rolebindings.authorization.openshift.io jenkins_edit

删除干净后,可以用命令 oc get all -o wide 验证

再来一次

oc new-app --template=jenkins-ephemeral --param=JENKINS_PASSWORD=welcome123

  • Copyrights © 2019-2024 John Doe
  • Visitors: | Views:

请我喝杯咖啡吧~