"仁扬" 发布的文章

公司大量使用微服务框架 go-micro,但框架作者已不再维护低版本(新版本已经商业化),只能自己动手了。

起因是我用 Go 1.16 编译,启动报错:

panic: qtls.ConnectionState not compatible with tls.ConnectionState

goroutine 1 [running]:
github.com/lucas-clemente/quic-go/internal/handshake.init.0()
        /go/pkg/mod/github.com/lucas-clemente/quic-go@v0.12.1/internal/handshake/unsafe.go:17 +0x118

跟进去看:

func init() {
    if !structsEqual(&tls.ConnectionState{}, &qtls.ConnectionState{}) {
        panic("qtls.ConnectionState not compatible with tls.ConnectionState")
    }
    if !structsEqual(&tls.ClientSessionState{}, &qtls.ClientSessionState{}) {
        panic("qtls.ClientSessionState not compatible with tls.ClientSessionState")
    }
}

发现 tls.ConnectionState 在是标准库的包 crypto/tls,也就是说,新版本的 Go 标准库的定义,和 github.com/marten-seemann/qtls 不兼容。

公司使用 Go 1.14 编译,程序是正常运行的。

翻了一大圈资料,都是让我降级版本:
https://github.com/ipfs/go-ipfs/issues/7597
https://segmentfault.com/a/1190000020124701
https://www.jianshu.com/p/253d08c50c44
https://www.cnblogs.com/huay/p/14491557.html
https://blog.csdn.net/Xiang_lhh/article/details/113814742

还真不能降版本!因为我电脑是 M1 芯片,必须使用 Go 1.16,只能硬着头皮改了。

翻了 go-micro 源码,Transport 定义了客户端和服务端的通信接口,支持 http、grpc、quic 等协议。

引用 外部 的一张 go-micro 架构图:

go-micro 架构图

我也搜到了一片文章,解释 QUIC 到底是个啥:

干货 | HTTP探索之路(一)- HTTP1/HTTP2/QUIC
https://zhuanlan.zhihu.com/p/102517430

言归正传,既然是 quic 不兼容标准库,那我们升级一下不就完了:

github.com/lucas-clemente/quic-go v0.12.1 -> v0.22.0

发现编译不通过——好家伙,新包直接改了接口定义!

对比了官方的更新,也就换了个方法名和包名,细节就不展开了,直接看我修复的代码吧:

https://github.com/Lofanmi/go-micro/commit/68bbf601cfa46b0c49c67f51e4e38e6a6f029f42

用法很简单,直接 replace 掉就 OK 了!

replace (
    github.com/micro/go-micro => github.com/Lofanmi/go-micro v1.16.1-0.20210804063523-68bbf601cfa4
)

如果还不行,再 replace 掉下面的包:

replace (
    github.com/golang/protobuf => github.com/golang/protobuf v1.3.2
    google.golang.org/genproto => google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1
    google.golang.org/grpc v1.30.0 => google.golang.org/grpc v1.26.0
    google.golang.org/protobuf => google.golang.org/protobuf v1.25.0
)

上面四个 replace 是工程内其他依赖的,我没办法测试只替换 go-micro 是否可以解决问题,所以也贴在这里,需要请自取哈。

先说八字流派

八字流派特别多。

不管是事业,还是婚姻感情,看法也不尽相同。我听说过的就有以下几种:

  • 格局:八字用神,专求月令;也有看月令透干的流派。
  • 盲派:铁口直断,根据四柱八字形象、干支组合等断大事件,出口往往戳中痛点。
  • 旺衰:以日干旺衰为核心,追求五行平衡,旺了,克泄;衰了,帮扶。主要分《滴天髓》派和新派。滴天髓派多体现在断语上,而新派更多倾向于公式化(一个土二个木各种占比计算之类)。
  • 禄命:听过,但没有见过。以年命为主看纳音和神煞。

这几种流派我们不讨论孰优孰劣,涉及的东西太多,了解甚浅,不好评价。但我觉得,格局很好用。

成大格者成大事。

格局看事业——张敬尧

《明通赋》:向官旺以成功,入格局而致贵。如何看事业,用一篇文章只能讲一丢丢丢丢丢。估计要肝个一百篇才能讲个七七八八。

想来想去,还是找个案例合适些。

张敬尧(1881-09-18 ~ 1933-05-07),字勋臣,安徽省颍州府霍丘县人,保定军官学校毕业。中华民国及满洲国军事将领,因与日本合作被国民政府军事调查统计局(军统)刺杀身亡。

《穷通宝鉴·八月乙木》有此命例:秋木盛,煞高有制,贵为都督,早年午运最佳,人后运不得地,故起伏不常,辰运癸酉年,被剌殒命。

张敬尧生于光绪七年闰七月廿五日卯时,八字如下:

辛丁乙己
巳酉卯卯 乾

丙申、乙未、甲午、癸巳、壬辰,五岁起运。

乙木,生于农历八月,七杀格。日时卯木禄神,旺。大抵伤官七杀,最喜身旺,有制伏为妙。

七杀也称偏官。经曰:人有偏官,如抱虎而眠,虽借其威足以慑群畜,稍失关防,不应其噬脐,不可不虑也。

丁火食神制月令酉金,七杀、食神旺,一看就很溜。辛坐巳,丁坐酉,长生之地。

时辰己土,喜还是不喜?偏财,喜。年支巳火伤官,忌。

喜忌分析完,一目了然。午运(1910 ~ 1914 年,30 ~ 34 岁)美滋滋,乙长生于午,丁禄于午。这五年应该是他人生最舒坦的。

1912 年,团长;壬子,合丁冲午,吉。

1913 年,旅长;癸丑,巳酉丑合七杀金局,不吉。

1914 年,师长;甲寅,合己,吉。

癸运(1915 ~ 1919 年,35 ~ 39 岁),癸,此处当偏印看,吉。

1916 年,总司令;丙辰,合辛、酉,透丙,不吉。

1918 年,省长;戊午,财食,吉。任湖南督军兼省长,纵兵殃民,甘心媚外。

1919 年,己未,吉。五四运动时,湖南人民开展驱张运动。

巳运(1920 ~ 1924 年,40 ~ 44 岁),巳,伤官透,不吉。

1920 年,被免职;庚申,合乙合巳,不吉。此年北洋政府被迫将其去职。

1922 年,壬戌,吉。奉系败北,张敬尧投奔直系吴佩孚。

壬辰运(1925 ~ 1934 年,45 ~ 54 岁),丁壬合,辰酉合,杀动,皆不吉。

1925 年,军长;乙丑,七杀得局,不吉。张敬尧投鲁军的张宗昌,被任命为直鲁联军第 2 军军长。

1926 年,副司令;丙寅,不吉。

1928 年,戊辰,合酉,不吉。张宗昌败北,张敬尧随之下野,逃往大连。

1932 年,投靠伪满政权。壬申,合丁,不正,吉。

1933 年,总司令;癸酉,酉为七杀白虎,都是凶神,不吉。5 月 7 日,在北平东交民巷六国饭店,被刺客袭击而身亡。

辛巳、丁酉,天干丁克辛,地支半合——辛是国家政府(日本、伪满政权)。表面上我弄死你,背地里却跟你相好,这不就是汉奸的象嘛。

壬运,合去食神,七杀生威。

酉聚白虎,也死于白虎。

林庚白先生批道(《人鉴·命理存验》):

乙木阴柔,虽秋生,得两禄不弱,惟辛金七杀太旺,喜丁食制之。

三十岁后,午运长生,又丁火食神见禄,必佳运。

癸丁相战,有己土制癸,反仇为恩,故屡立战功,位至湘督。

庚申流年,交入巳运,巳初有金,岁运皆杀,宜其不振,辛酉尤劣。

明年四十五,交入壬运,丁壬化木,化凶而吉,八月后必有动机。

丙寅丁卯,四十六七,又握重柄,戊辰已巳两年亦佳。

庚午交辰初乙木,五十、五十一两年,财权两旺。

壬申五十二,急流勇退,否则癸酉一年有凶。

“癸酉一年有凶”。

或许,这就是命吧。命该如此,半点不由人。

最后更新时间 2021-07-04.

本文整理自2ccc盒子iny的帖子 → 链接到原贴
破解 → 链接

一、绿色版介绍

  • 绿色版为完全版,没做任何的精简,也没有做任何的改动!
  • 绿色版不含任何破解,仅供研究,24 小时后请自行删除,如需继续使用 RAD Studio,请购买正版。

二、绿色版文件包说明

绿色版共包含 4 个文件包,分别为:

  • [必选] dotnetfx45_full_x86_x64.exe:Microsoft .NET Framework 4.5
  • [必选] RAD Studio 10.4.2 绿色版.7z:基础包
  • [必选] RAD Studio 10.4 Green 1.4.rar:绿化程序
  • [可选] RAD Studio 10.4.2 PlatformSDKs.7z:Android SDK、Android NDK

三、绿色版使用说明

  1. 安装 Microsoft .NET Framework 4.5,只安装一次即可,Windows 10 已自带,可以跳过此步;
  2. 解压 RAD Studio 10.4.2 绿色版.7z 到任意目录;
  3. 解压 RAD Studio 10.4.2 PlatformSDKs.7z 解压到绿色版的Extra目录 (10.4\Extra\CatalogRepository\);
  4. 解压 RAD Studio 10.4 Green 1.4.rar 解压到绿色版目录下 (10.4\RADStudioSydneyGreen.exe);
  5. 运行 RADStudioSydneyGreen.exe 可实现绿化和卸载。

四、下载地址

1. Microsoft .NET Framework 4.5 (Windows 10 已自带,可以跳过此步)

官方下载地址:http://download.microsoft.com/download/b/a/4/ba4a7e71-2906-4b2d-a0e1-80cf16844f5f/dotnetfx45_full_x86_x64.exe

2. RAD Studio 10.4.2 绿色版.7z (3.69GB,解压后 26.2GB)

下载地址:https://pan.baidu.com/s/1xmMoFKEt--Kud7_6lB7Dgg
提取码:je3q
MD5: 7C078BC1C78DE33A70F76D98A193E8F6
SHA1: 37F43F18E57FA6B5C8245169C2D024A26B047998

3. RAD Studio 10.4.2 PlatformSDKs.7z (2.31GB,解压后 5.91GB)

下载地址:https://pan.baidu.com/s/1TdS9B2t4ymcwrRQwqZKBiw
提取码:40w3
MD5: 34DD02D1EDE2BF62580C76F424E72C2F
SHA1: ED3C5D4E35DAB4E8B8ED07582317A042734719E2

4. RAD Studio 10.4 Green 1.4.rar(965KB)

下载地址:https://pan.baidu.com/s/1_YYv2QiQRJRXolH1u80bsg
提取码:0tod
MD5: 837FF4733D85FF4F7C77B803804AEC32
SHA1: 5F81CFE8BB39A4F983A63C64050ACCAFE86193AF

附:RAD Studio 10.4 Green Update History

-1.4

  • 支持RAD Studio 10.4.2

-1.3

  • 支持RAD Studio 10.4.1

-1.2

  • 修正部分环境变量路径错误

-1.1

  • 修正关联文件路径错误
  • 修正帮助文件路径错误
  • 修正卸载会连同 10.3 一起卸载的错误

-1.0

  • RAD Studio 10.4 绿化程序第一版

传统部署的坑:

1202 年了,如果你连 Docker 都不知道是什么,我建议买一本书看看——或者谷歌一下,博客已经写烂了。

为什么有这篇文章,是因为我在真正做容器化改造的时候,发现公司生产环境存在大量的坑:

  • 传统虚拟机部署,基本依赖克隆或者手工编译。由于人力原因,SRE 历来单传,编译出来的 PHP、扩展等二进制版本不一致;
  • 项目开发人员痛苦不堪——他没办法模拟出接近于线上一致的环境(碰不到摸不着,各种扩展版本都要自己去编译);
  • 新人入职都会灵魂拷问你一句——我怎么把线上的代码跑起来?
  • ……

用什么 Linux 发行版?

Ubuntu 应该是全球用户量最多的发行版了,嗯我说的是桌面这一块,折腾过的人都知道,出问题的时候开机会有 “检测到系统错误” 的提示,另外,网上提供的配置或者各种疑难杂症,改了不一定能生效,而且你还不确定改了会不会影响到别的,反正我是不敢用的哈哈(Manjaro 真香)。

CentOS 应该是大家最熟悉的,也是我见过最多应用在生产环境中的。它给我的感觉就是非常稳定,并且网上的资料是一搜索就展现在你面前,而你对着资料改配置,重载就生效,不会搞出什么问题。

公司的生产环境清一色 CentOS 6,但 CentOS 6 已经被官方弃用,不再提供 yum 镜像源,这也意味着很多包你都安装不了,所以你只能升级到 CentOS 7。

问题来了,我能升级吗?

这不得不说到之前线上出现过一个故障:

公司有一台发布构建机器,用来做代码部署,机器上安装了 NodeJS、Go 编译器等,有一天前端的同事说向 SRE 同学提了一个需求:

升级 NodeJS 到 v10 版本,因为以前的 v6 版本太旧了,SRE 同学也没多想,发现 CentOS 6 机器要升级 glibc 才行,于是运维的同事就升级 glibc 之后,升级了 NodeJS;

过了段时间有人部署某服务,该服务使用了 结巴分词 ,部署完发现线上挂了……

嗯,线上环境的 glibc 版本比较低,编译机的 glibc 版本高,部署过去不兼容直接就是启动不了,还好当时回滚的够快 :)

直接用 7 也不是不可以,统一就 OK,但要命的是,发现有些祖传的 PHP 扩展,已经失传了,能兼容但是你怎么保证不出问题对不对?

经历万般挫折,最终使用的是 CentOS 6.9,好在腾讯云有 yum 源,东拼西凑了生产环境的 PHP 扩展之后,开发环境已经完美投入使用。

就是因为这些事情,前前后后花了两三周的时间都在折腾镜像。

小而美 VS 大而全:

CentOS 是真的大!我自己也使用 7 重新打了一个镜像,发现不管怎么清理各种缓存,最终的镜像大小都接近 1G!

虽然说也不是不能用,但我就是有洁癖呀。最后还是选择了 alpine ,把体积减少到 100M 以内。

到这里可能有人问:我们生产环境用的 alpine 也就 60M 左右,没有那么大吧?

之前看过这个项目 Laradock ,它的特点是定制化非常强,基本都是打开一些环境变量就可以构建出你所要的镜像;

但我更倾向于,牺牲一些磁盘空间,制作一个统一的环境。为了方便,线上没必要按照项目复制扩展,维护自己的 Dockerfile,统一都放进去就好了,维护起来也比较方便。

生产环境使用什么版本?

公司目前大量使用 PHP 5.4 和 PHP 7.2,扩展版本比较混乱;

没有直接使用 nginx,而是使用 openresty 1.11.2(主要是传统 IDC 部署缺乏云上 WAF ,需要自行做好限流和 IP 防刷);

我提供的 Dockerfile 是 PHP 5.6 和 PHP 7.2 的最新版本,理论上可以直接升级;而 openresty 使用最新奇数版本,保证生产环境的稳定和安全。

一些细节(坑)

记录一下为什么要花这么长的时间整这个镜像,个人觉得下面列举出来的,都是非常宝贵的经验:

镜像:

  • 尽量合并 RUN 指令,减少镜像层数,从而缩小镜像体积;

apk:

  • 官方的镜像非常慢,所以使用了阿里云的镜像加速;
  • apk --no-cache 的使用,也可以缩小镜像体积,对于自己安装的扩展不要忘记 rm 掉没用的文件夹;
  • composer 安装私有仓库依赖 git 命令,所以它需要被安装;
  • git clone 私有仓库需要 ssh-key,我的实现方式是 base64 编码文件内容,再 echo 到对应的位置上去,这样的好处就是一个 Dockerfile 就可以到处走了,不需要额外的文件和 COPY 指令,既方便又减少层数!
  • 通过 apk 安装下来的扩展,需要手工 cp 到 /usr/local/lib/php/extensions/no-debug-non-zts-20131226/ 目录下;

文件权限:

  • 私钥的文件权限是 600,只有文件的拥有者具有读写权限,组里其他用户或者其他用户连读都不行,不这样做的话代码拉不下来(ssh 会报错),切记;

线上排障:

  • bind-tools 的作用在于方便线上定位问题——有时候你不得不进去容器,发现没办法测试 DNS 解析,你会特别痛苦;

环境标准化:

  • 统一应用目录 /www 和日志目录 /wwwlog;

文件权限:

  • 用户和用户组的 id,此处是 500(CentOS 6),CentOS 7 是 1000——如果你使用 NFS 共享文件系统,需要统一 www 的 uid,不然文件权限问题会令你抓狂;
  • 公司使用 www 用户,官方提供的 fpm 镜像自带 www-data 用户,我代码重度洁癖,所以就把它删了;
  • 定时任务建议使用 www 用户运行,原因是日志目录有可能是被运维的同事挂在到宿主机采集(一台宿主机一个 filebeat 进程,节省资源),而你使用 root 用户创建的某些文件夹,其他人可能写不进去,但还是留了后手——给 root 设置密码,遇到问题说不定可以 su 解决;

扩展:

  • 公司重度使用 RabbitMQ 消息队列组件,所以安装了 amqp 扩展,rabbitmq-c-dev 等基础包必须加上,不然没办法编译通过;
  • redis、bcmath、gettext、pdo_mysql、mysqli、mbstring、gd、zip、opcache 这几个扩展几乎都是必装的,其他的像 yaf、sysvmsg 等不需要的,大家可以自行删除;

php-fpm.conf:

  • 非常驻模式启动,容器才不会刚启动就退出了;
  • 修改子进程数量,还有超时等配置,这部分与线上环境是一致的;

php.ini:

  • 打开 cli 模式的 opcache 扩展,加速 PHP 的运行,主要是一些定时任务;
  • 关闭 PHP 的版本输出,这样别人访问我的网站就不知道我使用哪个 PHP 版本了,安全无小事!

适用于生产环境的 PHP 5 Dockerfile:

FROM php:5.6.40-fpm-alpine3.8

LABEL maintainer="??? <???@???.com>"

ENV TZ=Asia/Shanghai

RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
    # deps
    apk --no-cache add bind-tools \
        git \
        make \
        openssh-client \
        php5-mcrypt \
        php5-sysvmsg \
        php5-sysvsem \
        php5-sysvshm \
        tzdata \
        freetype-dev \
        gettext-dev \
        imagemagick-dev \
        libmemcached-dev \
        libpng-dev \
        libzip-dev \
        jpeg-dev \
        rabbitmq-c-dev \
        && \
    cp /usr/lib/php5/modules/mcrypt.so  /usr/local/lib/php/extensions/no-debug-non-zts-20131226/ && \
    cp /usr/lib/php5/modules/sysvmsg.so /usr/local/lib/php/extensions/no-debug-non-zts-20131226/ && \
    cp /usr/lib/php5/modules/sysvsem.so /usr/local/lib/php/extensions/no-debug-non-zts-20131226/ && \
    cp /usr/lib/php5/modules/sysvshm.so /usr/local/lib/php/extensions/no-debug-non-zts-20131226/ && \
    # DNS
    [ ! -e /etc/nsswitch.conf ] && echo 'hosts: files dns' > /etc/nsswitch.conf && \
    # timezone
    ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
    echo '$TZ' > /etc/timezone && \
    # /www
    # /wwwlog
    # /app
    addgroup -g 500 -S www && \
    adduser -u 500 -D -S -G www www && \
    mkdir /www && mkdir /wwwlog && mkdir -p /app && \
    chown -R www:www /www && chown -R www:www /wwwlog && chown -R www:www /app && \
    addgroup www tty && \
    sed -i 's/\/home\/www:\/bin\/false/\/home\/www:\/bin\/ash/g' /etc/passwd && \
    deluser --remove-home www-data && \
    # password
    passwd root -d "!!!Production!!!" && \
    passwd www  -d "!!!Production!!!" && \
    # ssh-key
    mkdir -p /root/.ssh && \
    echo ???==|base64 -d>/root/.gitconfig && \
    echo ???==|base64 -d>/root/.ssh/config && \
    echo ???==|base64 -d>/root/.ssh/id_rsa && \
    echo ???==|base64 -d>/root/.ssh/id_rsa.pub && \
    echo ???==|base64 -d>/root/.ssh/known_hosts && \
    chmod 600 /root/.ssh/id_rsa && \
    # composer
    wget -O /usr/local/bin/composer https://mirrors.cloud.tencent.com/composer/composer.phar && \
    chmod +x /usr/local/bin/composer && \
    /usr/local/bin/composer config -g repos.packagist composer https://mirrors.cloud.tencent.com/composer/ && \
    # ext
    docker-php-ext-configure zip --with-libzip && \
    docker-php-ext-configure gd --with-jpeg-dir=/usr/lib --with-freetype-dir=/usr/include/freetype2 && \
    pecl install -o -f amqp-1.10.2 && \
    pecl install -o -f memcached-2.2.0 && \
    pecl install -o -f imagick-3.4.4 && \
    pecl install -o -f rar-4.2.0 && \
    pecl install -o -f redis-4.3.0 && \
    pecl download yaf-2.3.5 && tar zxvf yaf-2.3.5.tgz && cd yaf-2.3.5 && phpize && ./configure && \
    make && make install && cd .. && rm -rf yaf-2.3.5 && \
    docker-php-ext-install bcmath gettext mysqli pcntl sockets pdo_mysql mysqli mbstring gd zip opcache && \
    docker-php-ext-enable amqp mcrypt memcached imagick rar redis sysvmsg sysvsem sysvshm yaf && \
    rm -rf /tmp/pear /var/cache/apk/* /tmp/* && \
    # php-fpm.conf
    echo "[global]"        > /usr/local/etc/php-fpm.d/zz-docker.conf && \
    echo "daemonize = no" >> /usr/local/etc/php-fpm.d/zz-docker.conf && \
    # www.conf
    rm -f /usr/local/etc/php-fpm.d/www.conf.default && \
    sed -i "s/www-data/www/g"                                                  /usr/local/etc/php-fpm.d/www.conf && \
    sed -i "s/pm.max_children = 5/pm.max_children = 128/g"                     /usr/local/etc/php-fpm.d/www.conf && \
    sed -i "s/listen = 127.0.0.1:9000/listen = 127.0.0.1:9056/g"               /usr/local/etc/php-fpm.d/www.conf && \
    sed -i "s/;pm.max_requests = 500/pm.max_requests = 1024/g"                 /usr/local/etc/php-fpm.d/www.conf && \
    sed -i "s/;request_slowlog_timeout = 0/request_slowlog_timeout = 5/g"      /usr/local/etc/php-fpm.d/www.conf && \
    sed -i "s/;request_terminate_timeout = 0/request_terminate_timeout = 30/g" /usr/local/etc/php-fpm.d/www.conf && \
    sed -i 's/;slowlog = log\/\$pool.log.slow/slowlog = \/proc\/self\/fd\/2/g' /usr/local/etc/php-fpm.d/www.conf && \
    sed -i "s/;access.format/access.format/g"                                  /usr/local/etc/php-fpm.d/www.conf && \
    # php.ini
    cp /usr/local/etc/php/php.ini-production                 /usr/local/etc/php/php.ini && \
    sed -i "s/;opcache.enable_cli=0/opcache.enable_cli=1/g"  /usr/local/etc/php/php.ini && \
    sed -i "s/expose_php = On/expose_php = Off/g"            /usr/local/etc/php/php.ini

WORKDIR /app

适用于生产环境的 PHP 7 Dockerfile:

FROM php:7.2.34-fpm-alpine3.12

LABEL maintainer="??? <???@???.com>"

ENV TZ=Asia/Shanghai

RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
    # deps
    apk update && \
    apk --no-cache add bind-tools \
        git \
        make \
        openssh-client \
        tzdata \
        freetype-dev \
        libmemcached-dev \
        libpng-dev \
        jpeg-dev \
        && \
    # DNS
    [ ! -e /etc/nsswitch.conf ] && echo 'hosts: files dns' > /etc/nsswitch.conf && \
    # timezone
    ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
    echo '$TZ' > /etc/timezone && \
    # /www
    # /wwwlog
    # /app
    addgroup -g 500 -S www && \
    adduser -u 500 -D -S -G www www && \
    mkdir /www && mkdir /wwwlog && mkdir -p /app && \
    chown -R www:www /www && chown -R www:www /wwwlog && chown -R www:www /app && \
    addgroup www tty && \
    sed -i 's/\/home\/www:\/sbin\/nologin/\/home\/www:\/bin\/ash/g' /etc/passwd && \
    deluser --remove-home www-data && \
    # password
    passwd -u root -d "!!!Production!!!" && \
    passwd -u www  -d "!!!Production!!!" && \
    # ssh-key
    mkdir -p /root/.ssh && \
    echo ???==|base64 -d>/root/.gitconfig && \
    echo ???==|base64 -d>/root/.ssh/config && \
    echo ???==|base64 -d>/root/.ssh/id_rsa && \
    echo ???==|base64 -d>/root/.ssh/id_rsa.pub && \
    echo ???==|base64 -d>/root/.ssh/known_hosts && \
    chmod 600 /root/.ssh/id_rsa && \
    # composer
    wget -O /usr/local/bin/composer https://mirrors.cloud.tencent.com/composer/composer.phar && \
    chmod +x /usr/local/bin/composer && \
    /usr/local/bin/composer config -g repos.packagist composer https://mirrors.cloud.tencent.com/composer/ && \
    # ext
    docker-php-ext-configure gd --with-jpeg-dir=/usr/lib --with-freetype-dir=/usr/include/freetype2 && \
    pecl install -o -f memcached-3.1.5 && \
    pecl install -o -f redis-5.3.4 && \
    docker-php-ext-install bcmath pdo_mysql gd opcache && \
    docker-php-ext-enable memcached redis && \
    rm -rf /tmp/pear /var/cache/apk/* /tmp/* && \
    # php-fpm.conf
    echo "[global]"        > /usr/local/etc/php-fpm.d/zz-docker.conf && \
    echo "daemonize = no" >> /usr/local/etc/php-fpm.d/zz-docker.conf && \
    # www.conf
    rm -f /usr/local/etc/php-fpm.d/www.conf.default && \
    sed -i "s/www-data/www/g"                                                  /usr/local/etc/php-fpm.d/www.conf && \
    sed -i "s/pm.max_children = 5/pm.max_children = 256/g"                     /usr/local/etc/php-fpm.d/www.conf && \
    sed -i "s/listen = 127.0.0.1:9000/listen = 127.0.0.1:9072/g"               /usr/local/etc/php-fpm.d/www.conf && \
    sed -i "s/;pm.max_requests = 500/pm.max_requests = 1000/g"                 /usr/local/etc/php-fpm.d/www.conf && \
    sed -i "s/;request_slowlog_timeout = 0/request_slowlog_timeout = 5/g"      /usr/local/etc/php-fpm.d/www.conf && \
    sed -i "s/;request_terminate_timeout = 0/request_terminate_timeout = 30/g" /usr/local/etc/php-fpm.d/www.conf && \
    sed -i 's/;slowlog = log\/\$pool.log.slow/slowlog = \/proc\/self\/fd\/2/g' /usr/local/etc/php-fpm.d/www.conf && \
    # php.ini
    cp /usr/local/etc/php/php.ini-production                 /usr/local/etc/php/php.ini && \
    sed -i "s/;opcache.enable_cli=0/opcache.enable_cli=1/g"  /usr/local/etc/php/php.ini && \
    sed -i "s/expose_php = On/expose_php = Off/g"            /usr/local/etc/php/php.ini

WORKDIR /app

适用于生产环境的 openresty Dockerfile:

FROM openresty/openresty:1.19.3.2-alpine-apk

LABEL maintainer="??? <???@???.com>"

ENV TZ=Asia/Shanghai

RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
    # deps
    apk update && \
    apk --no-cache add bind-tools \
        tzdata \
        && \
    # DNS
    [ ! -e /etc/nsswitch.conf ] && echo 'hosts: files dns' > /etc/nsswitch.conf && \
    # timezone
    ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
    echo '$TZ' > /etc/timezone && \
    # /www
    # /wwwlog
    # /app
    addgroup -g 500 -S www && \
    adduser -u 500 -D -S -G www www && \
    mkdir /www && mkdir /wwwlog && mkdir -p /app && \
    chown -R www:www /www && chown -R www:www /wwwlog && chown -R www:www /app && \
    addgroup www tty && \
    sed -i 's/\/home\/www:\/sbin\/nologin/\/home\/www:\/bin\/ash/g' /etc/passwd && \
    # password
    passwd -u root -d "!!!Production!!!" && \
    passwd -u www  -d "!!!Production!!!"

COPY conf/nginx.conf            /usr/local/openresty/nginx/conf/nginx.conf
pcre_jit             on;
user                 www www;
worker_processes     1;
error_log            /usr/local/openresty/nginx/logs/error.log error;
worker_rlimit_nofile 65535;

events {
    use                epoll;
    worker_connections 65535;
}

http {
    include      mime.types;
    default_type application/octet-stream;

    server_tokens off;
    sendfile      on;
    tcp_nopush    on;
    tcp_nodelay   on;

    server_names_hash_bucket_size 512;
    client_max_body_size          8m;
    client_header_buffer_size     32k;
    large_client_header_buffers   4 32k;

    proxy_buffers           32 128k;
    proxy_buffer_size       128k;
    proxy_busy_buffers_size 128k;

    client_body_timeout   10;
    client_header_timeout 10;
    send_timeout          30;
    keepalive_timeout     60;

    log_format main escape=json '{"@timestamp":"$time_iso8601",'
                                 '"scheme":"$scheme",'
                                 '"remote_host":"$host",'
                                 '"clientip":"$remote_addr",'
                                 '"bytes":$body_bytes_sent,'
                                 '"cost":$request_time,'
                                 '"referer":"$http_referer",'
                                 '"agent":"$http_user_agent",'
                                 '"time_local":"$time_local",'
                                 '"xforward":"$http_x_forwarded_for",'
                                 '"method":"$request_method",'
                                 '"request":"$request_uri",'
                                 '"uri":"$uri",'
                                 '"postData":"$request_body",'
                                 '"cookieData":"$http_cookie",'
                                 '"httpversion":"$server_protocol",'
                                 '"reqid":"$reqid",'
                                 '"remote_port":"$remote_port",'
                                 '"server_port":"$server_port",'
                                 '"status":$status}';

    fastcgi_connect_timeout      300;
    fastcgi_send_timeout         300;
    fastcgi_read_timeout         300;
    fastcgi_buffer_size          64k;
    fastcgi_buffers              4 64k;
    fastcgi_busy_buffers_size    128k;
    fastcgi_temp_file_write_size 256k;
    fastcgi_intercept_errors     on;

    gzip              on;
    gzip_vary         on;
    gzip_comp_level   5;
    gzip_buffers      16 8k;
    gzip_min_length   1k;
    gzip_proxied      any;
    gzip_http_version 1.0;
    gzip_disable      "msie6";
    gzip_proxied      expired no-cache no-store private auth;
    gzip_types        text/plain application/javascript application/x-javascript text/javascript text/css application/xml application/xml+rss application/json;

    server {
        listen      80 default_server;
        server_name _;
        return      444;
        access_log  /usr/local/openresty/nginx/logs/access.log main;
        include     add_header_reqid.conf;
    }

    include /usr/local/openresty/nginx/conf/vhost/*.conf;
}

嗯,真实的生产环境配置十分混乱,我做了格式化,大家拿去用吧 :)

阅读本文大约需要 2.9 分钟。

曾经的我是一名艺术生,如今是一名程序员。

聊起画画,相信很多人都有疑惑:同样都是画人物,为什么我画不像,或者说我根本就不知道怎么下手。

你不是一个人。给你们看看江苏考卷:

“我明明在画人,但看着好像在画鬼。”


实际上,要把一个人画得像他本人,是需要下苦功夫的。

作为一个过来人,我觉得有两方面:

第一,眼高才能手高,多剖析物体的造型,多看多学习优秀作品。

人类对这个世界的认知是由浅入深的。在我看来,画画和写代码是有很大共同点的。

在计算机的世界里,软件开发离不开“抽象”二字。

抽象,就是在一个具体的问题中,提取出共性的东西,以此来解决复杂的问题。

比如抽象出一个“登录”接口,毕竟在现实世界中,有很多很多的登录方式——QQ、华为、小米、微信……

既然是抽象,那它就是可以解决同类问题的。

很多网站的登录,都有QQ、微信登录,那么 A 写的代码 B 就可以直接拿来用了,这就是一种抽象!

工作这么多年,第一次发现原来 Ctrl+C 和 Ctrl+V 可以被讲得这么高大上。

画画也是同样的道理。

我不知道读这篇文章的人有没有接触过“素描几何体”:

“我不想画几何体,我只想学习怎么画人。”

我真的听过很多这样的话。

再看看下面几张图:

是不是越来越有感觉了?

素描几何体,也只是对世界万物的抽象罢了。

鼻头、鼻翼——球状物体;

鼻梁——梯形、长方体……

如果鼻子比较高,鼻头就是个大球、圆润;

如果鼻子比较塌,鼻球就比较平,那就把球体削掉一点……

眼睛呢?叫眼球吧,秒懂:

至于嘴唇,上唇中间的部位,叫做唇珠,可以简单理解为球体:

更细致一些,它还有顶面和底面,顶面夹起来又延伸到鼻子下方,形成人中……

新手画人真的太难了!

看看水杯,就一个圆柱体嘛,手柄会难画一些,可以分段拆着画。

音箱,就是一个大大的长方体,音箱上的喇叭是圆形的,正中间还有个小球体。

当然,我也不是说一定要从几何体开始,我见过也有部分人跳过这一步,直接走了第二步,天天画日日画,最终画得也不错。

没错,第二点,就是熟能生巧。

站在岸上学不会游泳。不说画人,没有基础的人,画个最简单的长方体都会画错。

为什么?除了透视问题(这个属于认知范畴),还有就是他不知道怎么下手,一根线都画不直。

脑:我知道怎么画了。

手:我是谁我在哪儿我不知道。

这个没办法,只能多多练习,而且时间长了,肌肉记忆会丧失。

可以看看于小冬是怎么画人物的,滑到最底下有视频~

快速勾勒出大动态,确定好头、身体、四肢的位置,

再深入刻画人物细节,

而不是一上来就陷入细节当中。

一切以大局为重!!!

新手画人基本都是,

我先画头,画眉毛,一二三四五六七八根,

画睫毛,一二三四五六七八九十根,画长一点,比较美,

画眼线,画眼角,画眼珠,

画鼻孔,

画嘴,

画腮红……

哦豁,化妆和画画?道理是一样的。

有些人颧骨高,想把颧骨往里收,妆该怎么化?

颧骨高且突出,就人为地把这个转折点往里面画一画,并弱化原来位置。

鼻梁塌,那就把鼻梁两侧的转折加强些。

多画,多化~

积累到一定程度,逐渐就是肌肉记忆了。

眼到手到,一气呵成。