书评:《细说明朝》

这本书在好几年前读过,大概是在刚刚对明朝的历史产生兴趣时,彼时觉得其中的皇帝们混乱无序,文臣武将交错驳杂,读这本书更多地只是和《明朝那些事儿》相互对照印证罢了。现在虽然仍然不能完全搞清楚明朝的重要人物,不过好歹能搞清楚皇帝们的传承顺序了,因而这本书读下来感觉全文脉络还是比较清晰的,流畅性也大大提升了。这本书虽名为 “细说”,但是却一点都不细,称为大纲更为合适,毕竟近三百年的历史也没办法在一本书里完全交代,只能浮光掠影地对准那些最显眼的人——好人以及坏人。

翻遍明朝正史中的十六位皇帝,称得上称职的只有太祖、成祖、仁宣二宗、孝宗和穆宗,如果再考虑在位时间和施政连续性,那么就只有太祖、成祖和孝宗三位了(其中成祖穷兵黩武,透支民力过甚,全赖仁宗监国支撑)。除了这六位以外,其他十个基本算得上是一个赛一个地混蛋,尤为混蛋的世宗和神宗也是在位时间最长的两个,占去了不到一百年。明朝有这些皇帝们在竟还能支撑近三百年属实难得,全仰赖前期不错的底子,以及一系列文臣武将的呕心沥血。

阅读更多

书评:《美好的七年》

这应该是最近读的这些书里唯一一本让我常常笑出声的书了。虽然这本书的背景是一位以色列作家在战争期间的生活点滴,但是字里行间丝毫看不出哀怨和喟叹,反而还在短小的篇幅中浸透了幽默感,这并非是没心没肺,而是消解苦难的最佳手段之一。我一向认为诚恳和幽默是最难模仿的两个特质(在苦难中品咂出幽默感更是一种非常高级的技巧,具备这种技巧的作家似乎只能用天赋来解释),本书的作者同时具备这两个特质,这使得这本书的阅读成为了一种享受。

这本书是以色列作家埃特加·凯雷特自述性质的散文集,虽然是散文,但并不全是全无逻辑、充斥着浮夸辞藻和无病呻吟的文字堆积,而是有很精致的结构和很紧实的逻辑,并且内容毫不枯燥,阅读堪称享受。“美好的七年” 从儿子出生开始到七年之后,从战争的片段开始,以战争的片段结束,作者收集了很多生活中和事业上的各种片段,用自己的视角和文笔加工之后写了出来。虽然战争是常驻的背景音,但这本书的主题却不是声讨和反对战争,而是对于生活深刻的热爱,这种发自心底的热爱也同样是文中幽默感的来源。

这本书并不长,但是其中的天地却很宽广,很值得一读。

阅读更多

书评:《菊与刀》

如果谈到世界格局和民族性格,那这本书肯定会出现在推荐列表上。我认为这本书最大的价值尚不在于对于日本人的民族性格的分析,而是在于这种分析的系统性上,这种系统性使得本书可以成为一本人类文化学的教材,从这种系统性中完全可以诞生一门新的学科。

阅读更多

书评:《那不勒斯四部曲》

这四本书是花了十多天一口气读完的,因此也就放在一起写一写。这本书像一部不怎么严肃的意大利近当代史诗,着眼于两个女性的成长——拉法埃拉·赛鲁罗和埃莱娜·格雷科,也即莉拉和莱农,在半个多世纪的荏苒中讨论了童年、友情、亲情、爱情、女性权利、意识形态、社会变迁等等话题。这本书长篇累牍,让我总是不想开始读,直到看到腰封上的 “我的整个生命,只是一场为了提升社会地位的低俗斗争” 这句话——以前听到过这句话,但是这时才知道是出自这本书,于是决定立刻开始读。

第一本书是《我的天才女友》,“天才女友” 指的是莱农(也就是 “我”)从小的朋友莉拉,主要内容是两个人和她们生活的世界在童年和青春期的故事,截止到莉拉的婚礼。

第二本书是《新名字的故事》大概是指莉拉在嫁给斯特凡诺·阿奇勒之后的新名字 “拉法埃拉·阿奇勒”

第三本书是《离开的,留下的》

第四本书是《失踪的孩子》

这本书并不想庸俗地表达什么 “垃圾堆里的百合花” 之类的主题,书中的人物包括主角都并不特别坏也不特别好,刨去事业因素来看就是极其普通的人,这也就让这本书有了在现实中扎根的立足点。

莉拉是一个疏离的人,一个漫不经心的,找不到方向的天才,意识游离在自己的灵魂之外,并不爱自己。莉拉因为家庭因素并没有继续读书,把自己的另一个可能性,自己真正喜欢的另一个可能性寄托在了莱农身上。

阅读更多

2023 年 01 月书单

书名 作者 作者国籍 出版社 类型 评分
潜规则 吴思 中国 复旦大学出版社 社会科学-政治军事 8.5
中国国家地理百科全书:河南、湖北、湖南 张妙弟 中国 北京联合出版公司 自然科学-科学普及 5.0

Docker Multi-Stage Builds

Docker 的 multi-stage 技术可以把不同的构建阶段分离开,方便修改和复用,同时还能更好地把缓存层组合在一起,避免重复劳动,还能保证最后运行时的干净纯粹,不会带入前边阶段的副产品。不过我在实际场景中遇到的问题比单纯的构建更加复杂一些——我不仅需要不同的构建阶段(build stage),还需要在不同的环境里构建同一个镜像,比如在本地和在 CI/CD 中。CI/CD 的特殊之处在于在前边的阶段中基本上已经完成了 dependency download, build, package 等一系列阶段,因此直接把 build 的结果拷贝到 Docker context 里执行 Dockerfile 的最后几步就可以了。如果复用一个 Dockerfile,那么基本上要做前边的很多重复工作,如果用两份 Dockerfile,则又会造成配置上的冗余,迟早会出幺蛾子。

为了解决这个问题,我打算使用 Docker 的 multi-stage 来做,本意是把 package 之后的几步合并到一个 stage 里,在前边的 build 阶段来区分不同的环境。就像下边的配置一样,设想中这个流程非常完美,Docker 可以根据 ENVIRONMENT 来区分不同的环境,并且在最后的 runtime 阶段中从不同的环境构建阶段中把二进制内容拷贝出来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
FROM ubuntu:22.04 AS build-base
FROM ubuntu:22.04 AS runtime-base

# 当前环境
ARG ENVIRONMENT=dev

# 本地构建阶段
FROM build-base AS build-dev
RUN build
RUN package
RUN cp . /app

# CI/CD 构建阶段
FROM build-base AS build-prod
COPY . /app

# 最终阶段
FROM runtime-base AS runtime
COPY --from=build-${ENVIRONMENT} /app /app
ENTRYPOINT [ "/app/main" ]

但是这样做有个非常大的问题就是 Docker 的 build arguments 是只在单个阶段之内管用的,因此倒数第二行的 COPY 压根不认识 ENVIRONMENT 这个变量,进而这个 Dockerfile 根本无法正常构建。找了很多解决方案,最终看到虽然在 Docker 某一个阶段内不认识其他阶段的 build arguments,但是在定义阶段本身的时候是可以复用的,也就是 FROM runtime-base AS runtime 这一行,在这里是可以用 ENVIRONMENT 这个变量的。因此思路就很清晰了,可以直接改成下边这种情形:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
FROM ubuntu:22.04 AS build-base
FROM ubuntu:22.04 AS runtime-base

# 当前环境
ARG ENVIRONMENT=dev

# 本地构建阶段
FROM build-base AS build-dev
RUN build
RUN package
RUN cp . /app

# CI/CD 构建阶段
FROM build-base AS build-prod
COPY . /app

# 最终阶段
FROM build-${ENVIRONMENT} AS runtime
ENTRYPOINT [ "/app/main" ]

但这样有个最大的问题,就是最后的 runtime 阶段直接继承前边 build 阶段,会把这些阶段运行过程中的副产品、垃圾文件和系统包带到最后,这显然极大地违背了 multi-stage 的初衷。继承还是要继承的,关键是不能从 build 阶段继承,那么自然而然地就想到再加上一层干净的 ready 阶段来过渡,保证 ready 阶段中的内容是纯粹的二进制,每个环境都有自己对应的 ready 阶段,然后分别把自己的二进制拷贝进去就行,如下配置:

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
FROM ubuntu:22.04 AS build-base
FROM ubuntu:22.04 AS runtime-base

# 当前环境
ARG ENVIRONMENT=dev

# 本地构建阶段
FROM build-base AS build-dev
RUN build
RUN package
RUN cp . /app

# CI/CD 构建阶段
FROM build-base AS build-prod
COPY . /app

# 本地准备阶段
FROM runtime-base AS ready-dev
COPY --from=build-dev /app /app

# CI/CD 准备阶段
FROM runtime-base AS ready-prod
COPY --from=build-prod /app /app

# 最终阶段
FROM ready-${ENVIRONMENT} AS runtime
ENTRYPOINT [ "/app/main" ]

这样就可以完美地解决上边的所有问题,除了多出两个几乎一样的 build stages 以外没有什么成本。只要在执行 docker build 的时候传进入对应的 ENVIRONMENT 参数就行。还要注意的是,一定要使用 Docker Buildkit 来执行,这样才会根据最后的 runtime 阶段有挑选地执行需要的阶段,否则 Docker 会傻乎乎地执行所有的阶段,这样就得不偿失了。

2022 年 12 月书单

书名 作者 作者国籍 出版社 类型 评分
克拉拉与太阳 石黑一雄 英国 上海译文出版社 文学名著-外国文学 7.0
隳三都:蒙古灭金围城史 周思成 中国 山西人民出版社 品读历史-专题研究 8.5
海边的卡夫卡 村上春树 日本 上海译文出版社 文学名著-外国文学 7.0
我们台湾这些年:一个台湾青年写给13亿大陆同胞的一封家书 廖信忠 中国台湾 重庆出版集团 社会科学-世界格局 7.5
了凡四训:中华人生智慧经典 袁了凡 明朝 中华书局 文学名著-古代文学 7.0
鹿川有许多粪 李沧东 韩国 武汉大学出版社 文学名著-外国文学 6.5
失明症漫记 若泽·萨拉马戈 葡萄牙 南海出版公司 文学名著-外国文学 9.5
错把妻子当帽子 奥利弗·萨克斯 美国 中信出版社 自然科学-科学普及 7.0
喜:一个秦吏和他的世界 鲁西奇 中国 北京日报出版社 品读历史-专题研究 7.5

书评:《了凡四训:中华人生智慧经典》

“命由我作

福自己求”

短小精悍的四篇文章,分别覆盖了立命、改过、积善和谦德四个方面。有趣的地方是这几篇文章不是围绕中国古代朴素的哲学观念来论证的,而是糅杂了儒释道三家之说,谈及某一话题时哪个趁手就用哪家之言。这种思想兼容的趋势越到近古越是明显。比如在《立命》篇中,既谈到了道家命术,也有释家 “修来世” 之说,还请来了《易》和《孟子》来辅助强化,整体风格竟颇为圆融。

全文的中心是颇有 “圣人之德” 的意味的:为生民立命,君子修德有盛名,今生阴德荫子孙,终生自省不断改过,君子谦谦等等,总结下来就是那句 “命由我作,福自己求”。所以在我看来,儒释道三家之言本质上还是为引出和强化孔孟之道,这仍然是一篇放在唐宋时期也并不违和的经典古文。

不过这是一篇原文加评注的综合之作,因而实际上【注释】、【译文】和【评注】占据了绝大多数的内容。通篇看下来注者也不免有水字数之嫌,虽然评注中有大量的内容,很是能补充二氏之学的知识背景,但终究与译文部分有着高度的重叠性,甚至很大一部分的评注都是直接抄了一遍译文,以此看来书中大概有三分之一强的篇幅都是重复内容。

了凡先生这四篇文章是值得反复读的,甚至背诵也不为过,尤其是对于高中生而言。不过再读时只读原文加上有限的注释就可以了,评注可免矣。

阅读更多