服务器 Docker 化笔记

五一期间折腾了一下服务器的 Docker 化,踩了好多的坑,写文记录下来。

起因

起因很简单,五一去玩了一圈,结果到处都是人,所以在家猫着总得折腾点什么。 在公司写东西日常使用 Docker,目前对 Docker 的操作也非常熟悉了,所以总想着把我的服务器 Docker 化

先说一下我的基础配置,Kimsufi 的 KS-7 主机,i3 处理器,8G 内存,2T 硬盘,100M 带宽。 内存很充裕,就可以放心的折腾 Docker 环境。事实上我最后弄完几个容器,实际服务器占用也就 500M - 700M 左右。

重装服务器

由于我的主机已经用了一阵,所以服务器里很多已经抛弃的东西,也有很多正在用的东西。首先要备份数据到其他地方,我还有其它的服务器,所以把有用的数据 rsync 送到别的服务器上。

Kimsufi 登入管理面板,重新安装最新版的 CentOS 7。配置 SSH Key,升级最新软件包和内核。Kimsufi 安装的时候要注意,一定要勾选 use distribution kernel 选项。 如果没有勾选这个选项,Kimsufi 会给你安装定制版的内核,我不太清楚定制版内核会带来什么优势,但是目前来看只会造成麻烦。所以一定要使用发行版自带的内核。

Alpine with CGO

今天折腾这个一天,记录下来免得未来踩坑

Alpine with CGO

Golang 很棒,静态编译十分方便。但是,它也不是 100% 静态编译的,因为它需要依赖glibc ( 标准C运行库 )。

而 Docker 最常用的 Apline 镜像,使用的是 musl 库,并不能愉快的运行 Go 程序

网上大部分教程都是教你,CGO_ENABLED=0 go build -a -installsuffix cgo,使用纯 Go 编译,不用 CGO 链接 glibc ,问题就可以解决了。

但是最麻烦的问题是,你需要引入 C/C++ 库的时候,你并不能禁用 CGO 。

幸好 Alpine 有包管理器,所以我们可以很愉快的安装所需要的库。(我之前尝试手动安装glic和libstdc++,很难弄)

解决Alpine缺少字体的问题

2019-02-11 农历己亥年上班第一天

好久没有写博客了,我这个博客是Hugo静态编译的,写一次还是蛮复杂的,而且上班以后基本没有什么值得写的东西,所以博客基本都在长草。

立一个FLAG,2019 博客不长草。

前言

我现在的这家公司基本都在用现代化的开发工具,所有程序写完都在docker环境下运行,我们公司dalao钦定的底包就是alpine。后续的问题都是Alpine没有自带默认字体造成的。如果你想快速知道怎么解决请直接看最后。

问题

我遇到的问题是这样的:

java.lang.NullPointerException at sun.awt.FontConfiguration.getVersion(FontConfiguration.java:1264)

Java报错

场景是公司买的快速开发框架jeeplus,自带一个数据导入功能,需要下载excel模板,当下载模板时触发NPE。

Ubuntu 18.04 必做操作

新开一个栏目,专门记录开发中常见的命令和操作

新装完Ubuntu Server之后要做几个操作,才能让他更好用:

  1. 更新软件源
  2. 安装必备软件
  3. 设置系统代理

Ringbuffer环形缓冲区

前言

环形缓冲区是很常用的数据结构,用途很广泛。我目前遇到的使用场景就是TCP分片转回TCP流,一个线程读取TCP分片拆包,写入缓存区,另一个线程从缓存区中读取,互相不影响。

为此Google了一番,发现了kfifo这个Linux内核的实现,十分精妙。

原理

基本原理

struct kfifo {   
    unsigned char *buffer;    /* the buffer holding the data */   
    unsigned int size;    /* the size of the allocated buffer */   
    unsigned int in;    /* data is added at offset (in % size) */   
    unsigned int out;    /* data is extracted from off. (out % size) */   
    spinlock_t *lock;    /* protects concurrent modifications */   
};

先看一下基本定义,buffer是数据缓存区,size是缓存区长度,in/out是输入输出指针位置(%size后就是真实指针了)。

size需要检测是否为2的次幂,不是的话需要升到2的次幂。方便后续计算。(可以看内核的roundup_pow_of_two实现)

in、out每次操作都+对应的读写长度,通过取模运算回落size区间。

data := kfifo.buffer[kfifo.out % kfifo.size:kfifo.in % kfifo.size]

data就是有效数据的缓存区区间。

快速取模

kfifo使用了二进制的位运算实现了2的幂取模运算,并且利用了无符号数的溢出做回绕。很精妙的设计。

首先,缓存区尺寸要取整为2的幂次,这样可以利用位运算进行取模。

M mod N = M & (N-1),当N为2的幂次时有效。

取模运算对于计算机来说运算速度也是很慢的(虽然你感觉不出来),而位运算就是分分钟的事了。

回绕

无符号数溢出后,就会变成0从头开始,借助这个特性可以绕开逻辑判断。