kubectl get secret MY-SECRET-NAME --namespace=ORIGIN-NS --export -o yaml |\
kubectl apply --namespace=TARGET-NS -f -
GTomatoD
I always have the problem of concentrate on something. For people like me, GTD(Get things done) work stream and tomato working method is very helpful. But I found apps are usually focus on either GTD or tomato working method. And that is where I came out the thought of combine these two things together.
Now you can not just get things done but also tomato done! : )
If you have any problem when using my App or you want something more in this App, please leave a comment below or just email me whatever you would like to say about this App.
My email address: flamelapp@gmail.com
一直以来无法专心的问题都困扰着我。对于像我这样的人来说,GTD(Get things done) 工作流和番茄工作法都是非常帮助的选择。但我发现各个App基本都专注于这两者的其中之一。这也是我想到把两者结合在一起的想法出现的地方。
现在您将不仅可以Get things done而且还能Get tomato done。:)
如果您在使用我的App时遇到了任何问题或者您希望这个App添加更多的功能,请在下方留言或者直接email给我您的想法。
我的电子邮箱地址:flamelapp@gmail.com
利用context和kubectx快速切换kubernetes集群
在使用kubectl操作kubernetes集群的过程中,可能会遇到需要操作不同集群的问题,例如本地的minikube集群和线上的部署集群,或是线上的测试集群和线上的部署集群,如果集群之间切换不频繁,也可以使用笨办法,比如准备多个config文件在/.kube文件夹下,要切换的时候就改config的名字。不过对于需要频繁切换操作集群的人来说,这个方法显然太麻烦了,当然也不够cool。
当然,k8s是非常完善的集群解决方案,肯定是考虑到了这个问题的,这里就用到了k8s的config文件的context(上下文)了。
如果你是从零开始配置两个集群的cluster, user等信息的,那么可以参照官方的这个文档
Define-clusters-users-and-contexts
这里就不详细说以上这种方法了,我们来说说已经存在了两个集群的config文件时如何简单的生成context,当然,在上述文档的后半部分,也有我要说明的这些,也可以去看英文原文,我这里是因为遇到了一个坑,所以详细解释一下。
首先说方法,我们都知道kubectl如果没有设置config相关位置的环境变量,那么其会默认去一个地方寻找,对于Mac来说,就是
$HOME/.kube/config
如果要自己指定一个config文件所在的位置,那么就要设置KUBECONFIG
环境变量,例如:
export KUBECONFIG=$KUBECONFIG:$HOME/.kube/config
而如果有两个集群的配置文件呢,其实就可以非常简单的直接加在环境变量的后面,然后让kubectl自动为我们生成context,例如:
export KUBECONFIG=$KUBECONFIG:$HOME/.kube/config:$HOME/.kube/config-2
注意:可以使用
kubectl config view
来查看目前的context的情况
那么坑在哪里呢,由于两个集群的配置文件可能是管理员只分配给你自己使用的,那么用户名就可能是相同的,在用户名相同的情况下,如果集群的连接启用了TLS验证,那么kubectl自己融合的config文件就会使用相同的client-certificate-data和client-key-data,如果两个集群在同一服务商的同一片网络下还好,可是如果是在不同的网络下,那么就会出现只能连接上其中一个,而另一个集群无法连接的情况,这种时候,我的解决办法是修改用户名,但要注意,在config里的context下,可以看到user和name两个字段,我们要修改的是user字段,这里只是一个名称,不影响集群侧的用户验证,修改完user字段,记得翻到users字段下,那里面有一个name,这个name的值应该和刚刚修改之前的user字段中的值一样,把这里也修改成同样的新值,保存,重新配置环境变量使之生效,这时候就可以使用了。
至于官方提供的切换集群的方法,在上述文档中也能找到,这里也不在赘述,这里主要介绍一个第三方工具来帮我们更快捷的做这个事:
kubectx
这个工具可以给context指定alias并快速的切换他们,简单的介绍一下
kubectx : 列出目前所有的context kubectx <NAME> : 切换到<NAME>对应的context kubectx - : 切换到上一次的context kubectx <NEW NAME>=<NAME> : 给<NAME>context命名一个新名字 kubectx <NAME>=. : 给当前context命名一个新名字
可以看出,在完成了上述config文件自动融合之后,使用这个工具就可以快速的切换不同的操作集群,同时这个工具还支持bash/zsh的tab自动补全,以及fzf这个快速选择工具,可以说从此以后切换集群就可以如丝般顺滑了,不过缺点就是kubectx这个工具会影响对kubectl的自动补全,全看各位的习惯了
睁眼还(Debts)介绍页面
如果有问题意见或建议请在本篇文章下留言。或者,
发送邮件到本人的邮箱:flamelapp@gmail.com
If you have any problem or suggestion please leave a comment under this article. Or,
You can send an email to my mailbox: flamelapp@gmail.com
iOS开发如何浏览模拟器中的coredata数据
在后端开发使用go语言时,网络包的使用经历了beego,fasthttp等包,最终又用回了go的官方http包(当然这个包最近各种升级例如支持了优雅退出啊等等就算是另一说了),发现还是尽量用官方的东西更好一些。
iOS开发也是这样,iOS开发中本地数据库操作也有不少的解决方案,从iOS自带的coredata,到FMDB,再到完全不依赖sqlite的Realm,我原本也使用了一段时间的realm,但有两点让我很不爽
- 毕竟是第三方项目,总是要更新,如果你是使用OC语言的,那么还好,但如果你是像我一样使用swift语言的,那么swift的更新外加realm自身的更新能够把你烦死
- realm对于字段变更的操作非常不友好,如果还没生成数据还则罢了,如果已经生成了数据,那么不好意思,请按照realm提供的反人类一样的方法一步一步执行,而且你还得关注当前的字段版本,比如最老的版本是1.0,之后你又推出了1.0.1和1.0.2的更新,那么你就至少得写下1.0到1.0.2和1.0.1到1.0.2的两个版本迁移的代码块,因为我们是在面向C端的,你永远不知道你的用户什么时候更新你的APP,所以你得提供所有老版本到最新版本的转化方式。
综上,最终我还是决定用回coredata,至少官方的支持还是可以的,swift版本也不用像OC一样需要几个步骤生成连接代码等等,直接在model文件里操作好,背后的一切工作swift都已经帮你完成了,当然,这里我要强调一点,那就是本地数据库并不应该存储多么巨大复杂的数据,如果一个用户一天在你的APP里生成10条数据,一年也不到4000条,完全到不了需要拼速度和优化的时候。
终于说到正题,既然使用了coredata,那么调试的时候免不了会想要查看一下数据或者手动更改数据,可是模拟器的数据一是藏得深,二是并没有直接浏览更改的方式,我们分别解决一下。
获取数据路径
在AppDelegate文件的didfinishlaunch中加入下面这一行代码
print(FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask))
这样会把当前模拟器的文件路径打印出来,有了路径,就好办了,比如可以在terminal里直接open,然后应该会看到一个名为“Application Support”的文件夹,里面就是对应的.sqlite文件
查看.sqlite文件
有了文件,如何查看又是个问题,下面提供以下几个方法,可以根据自身情况自由选择
- (推荐)使用sqlite3直接在terminal里查看
- 对于习惯于用命令行操纵MySQL的人来说,sqlite3的操作应该没有什么入门难度,也是比较推荐的方法,Mac又是自带Python和sqlite3的,如果找不到,那么可以从如下网站来进行安装:https://www.sqlite.org/download.html
- (推荐)可视化方案:DB Browser for SQLite
- 对于习惯于可视化管理的人来说,我推荐这个方案,本身是一个在GitHub上的开源项目,马上要突破1万星,安全和可靠性都有保障,还是免费的,只要把.sqlite文件拖到这个APP内就可以自动打开,当然coredata自动命名的表名和你自己命名的略有区别,比如我创建了一个Objectives的Enity,在这里看到就是ZOBJECTIVES,自己找一下就可以了
- GitHub地址:https://github.com/sqlitebrowser/sqlitebrowser
- 官方网页直接下载打包好的版本:https://sqlitebrowser.org
- 可视化方案:Base 2
- 功能更完善,界面更好看,但没有优先推荐的原因是其是收费的,20欧的售价其实并不算高,不过没有特别专业复杂的需求,用上面的就足够了
- 官网地址:https://menial.co.uk/base/
- 可视化方案:Firefox sqlite插件
- 这个大概就是特定适合使用火狐浏览器的人群了吧,我本身不用火狐,所以各位如果用的也可以测试了给我反馈一下
- (不推荐尝试)可视化方案:Core-Data-Editor
- 同样是GitHub上的一个开源方案,但由OC写成,同时也只支持OC,同时需要有一个初始的适配过程,并且不能直接打开.sqlite文件
- GitHub地址:https://github.com/ChristianKienle/Core-Data-Editor
在kubernetes集群中使用私有镜像源
最近公司迁移到了新集群,为了确保服务上线后的稳定性,所有的应用上线之前都要在本地的minikube上跑一下,但原本在集群上用得正常的yaml,在minikube里就无法正常拉取docker镜像,Google一番之后被kubernetes的官方文档搞得一头雾水,拉到最下面才找到了原因,其实好好研究一下yaml就能发现不同的点,即yaml里有这样一行
imagePullSecrets
当deployment指定了特定的secret之后,其便会遵循这个secret中的docker镜像源的信息来拉取镜像,创建非常简单,只要
$ kubectl create secret docker-registry myregistrykey --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL secret "myregistrykey" created.
其中email是选填的
在yaml里就可以直接这样写:
apiVersion: v1 kind: Pod metadata: name: foo namespace: awesomeapps spec: containers: - name: foo image: janedoe/awesomeapp:v1 imagePullSecrets: - name: myregistrykey
参考资料:
https://kubernetes.io/docs/concepts/containers/images/#using-a-private-registry
Mysql更新排名的取巧实现
最近的项目连续遇到了对用户排名的需求,一个要求不用并列,一个要求同分并列,因为用户体量的考虑,拒绝了实时更新(即每个用户查询排名时获取排名),改为定时更新,在网上查了大量的MySQL排名算法之后,发现大部分的文章是以查询时获取来实现,而非定时更新所有人的排名,所以经过一番研究之后自己写了一个算法,欢迎斧正
首先我们假设有一张user表,其中有四个字段,score,rank,score_rank,join_time分别代表用户的分数,排名,获取排名时的分数,及用户加入时间
首先是不考虑并列的情况
SET @r = 0 UPDATE user SET `rank` = @r := (@r + 1), `score_rank` = `score` WHERE `score` != 0 ORDER BY `score` DESC, `join_time` DESC // 因为没有并列,所以增加一个排序
然后是考虑并列的情况
SET @r = 0; SET @l = 0; SET @s = 1; UPDATE `user` SET `rank` = ( CASE WHEN `score` = @l THEN @r := @r + (@s := @s + 1) - @s ELSE @r := (@r + @s) + (@s := 1) - 1 END), `score_rank` = @l := (`score`) WHERE `score` != 0 ORDER BY `score` DESC
这里唯一需要注意的事情就是MySQL中的变量问题,变量只能在两个地方赋值,SET或SELECT时,其余的地方只允许在变量赋值给其他字段时才允许被修改,所以就是在这里我们开始取巧,来解释一下并列时的思想:
r,l,s分别是当前排名,当前排名的分数,和当前同分的人数
当某一行的数据与上一行的分数相同时,即 score
= @l,那么这时应该给rank赋值为当前的排名,但同时应该更新同分人数,所以我们这样来实现:@r := @r + (@s := @s + 1) – @s,这样s实现了自增,但对返回结果r没有影响
当某一行的数据与上一行的分数不同时,则应该给rank赋值r+1,但同时我们希望给l赋值当前的分数,并把同分人数s归为1,则选择这样实现:@r := (@r + @s) + (@s := 1) – 1
关于速度
这个算法在我这边的模拟测试中,三万条的数据排序用时0.4秒,所以肯定不能作为实时处理,计划是每天定时更新一回,操作时间也算是可以接受了。不知道其他算法的时间是会是多少,欢迎提供下对比。
Golang生产环境中time包的zonefile.zip问题
前段时间给程序加了个功能,打印时间按照时区打印,具体看起来是这样
loc, _ := time.LoadLocation("Asia/Chongqing") return time.Now().In(loc).Format("2006-01-02 15:04:05")
在本地运行没有丝毫问题,于是就想当然的推到了线上,结果线上的环境在进行到这步的时候直接panic了,嗯,看来是过于的自信导致了问题,明显loc是nil了,那么打印下错误吧,结果看到了这么一行:
open /usr/local/go/lib/time/zoneinfo.zip: no such file or directory
于是瞬间就明白了,我们线上使用的是docker镜像,复制到容器里的go程序也是编译好的二进制文件,所以容器里没有go环境,导致在本地能正常运行的程序在线上因为缺少对应文件而panic。
知道了问题,就好解决了,当然这里可以直接换加了go环境的镜像,但是明显这样违背了docker作为线上生产环境的初衷,即最小可用,加入了go环境会直接把大量的冗余数据加入到容器中,使单个容器的体积直接倍增,所以我们只需要把这个特定依赖的文件复制到容器中即可,在Dockerfile中加入这样一段:
COPY ./zoneinfo.zip /usr/local/go/lib/time/zoneinfo.zip // 这里我把这个文件也在本地复制到了我的项目中,因为我们的打包上线工作由线上的CI服务来完成,如果是在本地打包,那么可以直接复制原文件 COPY /usr/local/go/lib/time/zoneinfo.zip /usr/local/go/lib/time/zoneinfo.zip
最后说一句,下划线无视error什么的,是真不可取啊,吸取教训把上面的代码也换成了
loc, err := time.LoadLocation("Asia/Chongqing") if err != nil { LogError("parse location err:", err) loc = time.Local } return time.Now().In(loc).Format("2006-01-02 15:04:05")
升级MacOS10.13 High Sierra导致PHPMyAdmin无法正常显示的问题
升级了新的版本之后,一切介正常,唯独发现pma打不开了,变成了一堆php代码,猜想是自带的Apache出了问题,参考网上其他教程,打开了httpd.conf,发现果然和php有关的那个loadmodule被注释掉了,打开,重启Apache,无果。继续Google,发现还要加上AddType和AddHandler,加上,重启Apache,仍然无果,但发现php info检测的代码可以正常打开了,遂怀疑是自带的PHP升级了,不再兼容当前版本的pma了,于是按照官方流程升级pma,重新打开,正常工作,解决战斗。
以下是详细三部曲:
-
修改httpd.conf, 开启PHP loadmodule
打开Terminal,输入:sudo nano /etc/apache2/httpd.conf, 对httpd.conf进行编辑,按ctrl+W,搜索php7_module,找到:#LoadModule php7_module libexec/apache2/libphp7.so,将此行前的#号去掉,ctrl+O保存(此处可能弹出finder,关掉即可),ctrl+X退出
参考文献: PHP精通 mac本地安装php环境 找不到webserver 更改php文件目录 运行
-
修改httpd.conf,增加php文件支持
同上,搜索IfModule,在任意位置添加如下代码:
<IfModule php7_module>
AddType application/x-httpd-php .php
AddType application/x-httpd-php-so
<IfModule dir_module>
DirectoryIndex index.html index.php
</IfModule>
</IfModule>
参考文献:PHPMyAdmin showing code instead of webpage
-
升级到最新版本的pma
- 从以下网址下载最新版本的PHPmyadmin:https://www.phpmyadmin.net/downloads/
- 重命名旧的pma文件夹(例如:phpmyadmin-old)
- 解压并复制并重命名刚刚下载好的新版本pma到需要的位置(例如:phpmyadmin)
- 从旧的文件夹中拷贝config.inc.php文件到新文件夹中
- 测试是否一切正常工作
- 删除旧文件夹
翻译自官方文档:phpMyAdmin-Docs-安装-从旧版本更新
PS:Reference websites may require ladders.
Docker-Go 交叉编译运行Go程序
最近在学习docker和kubernetes,无奈本机搭了一个minikube无论如何无法启容器,k8s的日志就只告诉说没起来我在重启,剩下什么原因也不说,于是决定先在本地docker启动一下看看。
原本的后端应用上线是我写好之后由我的boss统一上线的,所以Dockerfile也不是我写的,当然线上能跑,本地就肯定能跑啦,于是直接docker build,docker run,然后就出现问题了
./main: line 1: syntax error: unexpected “(”
随便搜了一下,发现基本上出现这个问题是因为运行程序的内核不同,然后仔细研究了一下Dockerfile,发现使用的是alpine的镜像,这个镜像的特点就是非常小,只有几兆,而且对比了一下公司的Dockerfile和golang官方alpine镜像的Dockerfile,发现我的Dockerfile里并没有集成go语言环境,而是直接将编译好的程序拷贝到镜像中,那么问题其实就可以确定了,我本地编译的基于Mac的go程序,即基于darwin内核的go程序,而alpine是基于Linux的内核的,自然无法运行。
知道了问题解决方法就很好办了,如果使用liteIDE的同学更是省事,直接删掉原本编译好的程序,选择cross-linux64环境编译就好(不用去改现有的darwin环境)
就算不是使用的LiteIDE,那也可以使用如下语句打包:
cd $GOPATH
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 ./make.bash 以上两步是为了生成linux平台所需要的工具和环境,只需要运行一次即可,如果使用liteIDE的话在切换环境的同时就会自动帮你准备好这些的
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build 再次运行docker,成功启动容器!