新程序员003:云原生和全面数字化实践

来源:https://e.jd.com/30797971.html

目录

  • 卷首语:开源云原生和数字化新实践
  • 云原生时代的开发者
  • 专题导读:云原生时代的开发者
  • 云原生的定义及其关键技术
  • 中国云原生用户调查报告:技术应用及应用建设现状
  • 2021云原生开发者现状:K8s稳居容器榜首,Docker冲顶技术热词,微服务应用热度不减
  • Kubernetes联合创始人Brendan Burns:Kubernetes及其未来
  • 云原生与大数据、AIoT、开源的碰撞之路——专访小米崔宝秋
  • 基础设施即代码:一场变革即将到来
  • Kubernetes与云原生运行时的前世今生
  • Serverless:从云计算的默认编程范式到生产力
  • 混沌工程+韧性工程:云原生时代可靠性治理的“王炸”
  • API——现代软件基石与数字世界的连接者
  • 云原生时代,如何构建一款简单易用且安全的应用管理平台?
  • Kubernetes生产实践下的可观测性及故障定位
  • 降本增效——美团集群调度系统的云原生实践
  • 火山引擎张鑫:“原生云”时代的四个改变
  • 大规模服务治理的云原生实践
  • Dubbo在云原生时代的进化之道
  • 网易轻舟服务网格落地实践
  • 混沌工程在中国工商银行的应用实践
  • 开源云原生大潮下的消息和流系统演进
  • Network Service Mesh:让电信网络虚拟化迈向云原生时代
  • 云原生运行时的下一个五年
  • 云原生时代的异地多活架构畅想
  • 云原生时代开发者,如何“变”与“不变”?
  • 全面数字化转型
  • 程序员的数字化转型
  • 蒋涛对话英特尔中国区董事长王锐:数字化已成为推动世界革新的原动力
  • 企业数字化转型的前世今生
  • 企业数字化转型路径和实现技术
  • 数字化转型方法论:数字化转型的失败原因及成功之道
  • 数字化转型的锦囊妙计:数字化平台
  • “离·坚白,合·同异”:微软数字化转型实践的思考
  • 构建新一代数据服务与管理平台的背后思考
  • 阿里云张瑞:程序员3.0时代到来
  • 基于云原生技术突破数字化软件生产瓶颈
  • 数字化就是释放比特的能力
  • 字节跳动的“数字化原生”之路
  • 以数据治理为价值驱动的产业数字化转型
  • 企业数字化转型:因企制宜,久久为功
  • 狭义工业互联网底层体系架构及应用部署
  • 施耐德电气:开放自动化是工业控制系统的未来
  • 工业数字化:IT+OT的数与智
  • 基于数字孪生理念重新思考、架构和实现新一代工业软件
  • 超融合时序数据库:消除工业数据“孤岛”
  • 百味
  • 《神秘的程序员们》之高并发需求

前言

  我们正在进入一个开发范式转移的大时代!

  十年前,Netscape创始人、硅谷著名投资人马克·安德森(Marc Andreessen)预言“软件正在吞噬世界”;数年后,软件里90%以上的代码都是开源代码,“开源正在吞噬软件”;如今,“云原生吞噬开源”,开源项目正在向云化演进。

  近年来,容器、虚拟化、DevOps等技术快速发展,将整个开发过程、开发流程带入云端,开发范式发生巨变。同时,Kubernetes、微服务、Service Mesh等一系列新技术规范涌现,开发模式、开发工具、开发成果甚至开发商业模式都在迭代升级。

  我们已经从过去的互联网时代步入移动互联网、云计算和大数据的时代,逐步进入全新的云原生时代。在云原生的发展道路上,开源有着非常关键的作用,它推动了云原生的发展。同样,云原生也为开源带来了最好的商业化模型。PaaS、SaaS以及IaaS服务都已进化到更加原生(Native)的状态,全面云化要来了!

  未来,开发者的代码调用等各种服务都将被云化,随之而来的是服务将拥有更好的弹性,用户体验也将提升。当开源项目被云化后,其收入模型将更加清晰,用户能够得到最新、最可靠的服务。一方面,云原生等新技术顺应市场与企业的需求而生,另一方面,越来越多的企业正在借助云原生应用架构助力业务的数字化转型。

  当数字化成为当下社会的主旋律之一时,企业对技术力量的需求也将不断升级。在《新程序员·开发者黄金十年》专辑里,我们曾谈到中国正迎来开发者市场的三大红利:人人都是开发者、家家都是技术公司、十万亿开发者新生态。而今,我们已经处在了全面数字化的时代,数字化正在吞噬传统行业。

  当业务皆被数字化和数据化以后,企业的竞争力是什么?答案是:你所拥有的开发力量。

  2021年,CSDN注册用户数量增长了近700万,实名总用户数3200万。这意味着,企业对开发者的需求仍在持续上涨。在数字化转型趋势下,开发者的机遇与挑战并存。开发者不仅要掌握新一代开发范式、学习新一代的云原生技术,未来也将朝着两大方向发展:一个方向是升级为架构级工程师,去帮助开发者开发更好的程序;另一个方向则是转变为业务专家,向以低代码驱动企业的业务发展。

  一个拥有复合能力的程序员才能拥有更多的成长机会。随着技术开发范式的变化,数字化转型加速实现,开发者最需要做的仍然是不断学习、提升自我。

  在《新程序员.003》中,我们聚焦“云原生时代的开发者”与“全面数字化转型”两大主题。阿里、字节跳动、网易、快手、亚马逊等互联网大厂的云原生技术的赋能者,从技术定义、技术应用、实践案例分享等方面,以直击内核的硬核输出全面解析云原生,帮助开发者在云原生时代快速找到适合自身发展的技术范式。同时,我们也将对微软、英特尔、华为、施耐德、西门子等首批开启数字化转型的企业展开报道,通过十多位技术专家分享的鲜活案例,一窥金融、新零售、工业物联网等领域的数字化转型成果,帮助更多关注数字化转型的开发者从先驱者的经验中获得启迪。

  微软(中国)首席技术官韦青在分享他对微软数字化转型实践的思考时谈到:“真正进入数字化转型深水区的公司,会越发认识到转型的不易,也会发现很多理论性知识与现实脱节的情况。”然而,我们相信,数字化转型已是大势所趋,未来将有更多行业逐步进入全面数字化的时代。


使用 Kaniko 在Kubernetes平台上构建容器镜像

我们之前使用Jenkins构建容器镜像,做法是 Jenkins容器挂载宿主机的socket文件到容器内部,容器内部运行 docker build 就行。

但是这样有一个问题。如果宿主机的 docker daemon 重启的话,必须把Jenkins容器也重启一遍(因为原有socket文件已失效了,但是容器内部是不知道的,还用着原有的socket文件),否则就会报错。

另外由于 /var/run/docker.sock 文件是root权限,将其挂在在容器里就存在风险了,所以挂载socket文件不是一种优雅的 docker build 方式。

kaniko

Kaniko是谷歌开源的一款用来构建容器镜像的工具。Kaniko 不依赖于Docker daemon进程,它在用户空间根据 Dockerfile 的内容逐行执行命令来构建镜像,这就和宿主机上的docker解绑了,更加安全可靠。

Kaniko 以容器镜像的方式来运行的,同时需要三个参数: Dockerfile,上下文,以及远端镜像仓库的地址

  1. Kaniko会先提取基础镜像(Dockerfile FROM 之后的镜像)的文件系统
  2. 根据Dockerfile中所描述的,一条条执行命令,每一条命令执行完以后会在用户空间下面创建一个snapshot,并与存储与内存中的上一个状态进行比对,如果有变化,就将新的修改生成一个镜像层添加在基础镜像上,并且将相关的修改信息写入镜像元数据中。
  3. 等所有命令执行完,kaniko会将最终镜像推送到指定的远端镜像仓库。

demo

$ cat Dockerfile
FROM alpine:latest
    
MAINTAINER <devops008@sina.com xiaomage>
    
RUN apk add busybox-extras curl
    
CMD ["echo","Hello DevOps"]

在kubernetes cluster上面创建一个pod,yaml文件如下:

apiVersion: v1
kind: Pod
metadata:
name: kaniko
spec:
 containers:
 - name: kaniko
   image: gcr.io/kaniko-project/executor:latest
   args: ["--dockerfile=/workspace/Dockerfile",
          "--context=/workspace/",
          "--destination=dllhb/kaniko-test:v0.4"]
    volumeMounts:
      - name: kaniko-secret
        mountPath: /kaniko/.docker
      - name: dockerfile
        mountPath: /workspace/Dockerfile
        subPath: Dockerfile
restartPolicy: Never
volumes:
      - name: dockerfile
        configMap:
          name: dockerfile
      - name: kaniko-secret
         projected:
         sources:
         - secret:
              name: regcred
              items:
                - key: .dockerconfigjson
                  path: config.json
  • args 部分

    这部分就是上面所讲的,kaniko运行时需要三个参数: Dockerfile(–dockerfile),上下文(–context),远端镜像仓库(–destination)

  • secret 部分

    推送至指定远端镜像仓库需要credential的支持,所以需要将credential以secret的方式挂载到/kaniko/.docker/这个目录下,文件名称为config.json,内容如下:

{   
    "auths": {
        "https://index.docker.io/v1/": {
            "auth": "AbcdEdfgEdggds="
       }
    }
    
}

其中auth的值为: echo"docker_registry_username:docker_registry_password"|base64

参考资料


pandoc 转换 markdown 为 pdf

一、安装

sudo apt install \
  pandoc \
  texlive-latex-base \
  texlive-fonts-recommended \
  texlive-extra-utils \
  texlive-latex-extra \
  texlive-xetex

二、背景介绍

Pandoc 可以很方便地对不同 Markup 语言的文件进行格式转换,因此被誉为格式转换的「瑞士军刀」。使用 Pandoc 把 Markdown 文件转为 PDF 文件,实际上包含两个步骤:

  • 第一步, Markdown 文件被转为 LaTeX 源文件。
  • 第二步,调用系统的 pdflatex, xelatex 或者其他 TeX 命令,将 .tex 文件转换为最终的 PDF 文件 。

Pandoc 默认使用的 pdflatex 命令无法处理 Unicode 字符,如果要把包含中文的Markdown 文件转为 PDF,在生成 PDF 的过程中会报错。我们需要使用 xelatex 来处理中文,并且需要使用 mainfont 选项指定支持中文的字体。

pandoc --pdf-engine=xelatex -V mainfont="XXX" test.md -o test.pdf

三、安装和查看本机上的中文字体

安装字体

apt-get install fontconfig xfonts-utils # 安装fc-cache
apt-get install ttf-mscorefonts-installer # 微软的TrueType 核心字库
apt-get install ttf-wqy-microhei  #文泉驿-微米黑
apt-get install ttf-wqy-zenhei  #文泉驿-正黑
apt-get install xfonts-wqy #文泉驿-点阵宋体

我是debian环境,字体位置,/usr/share/fonts

fc-list :lang=zh

image-20220310121348796

四、转换pdf常用参数

  • –latex-engine=pdflatex/lualatex/xelatex

–latex-engine用来指定转换PDF格式时LaTeX引擎,默认情况下是pdflatex,但是由于pdflatex不支持中文,因此需要将引擎设置为xelatex

  • –template=FILE

使用FILE指定的文件作为输出文档的自定义模板。可将模板文件放置任意处,只是指定FILE时需要该FILE的路径。

  • –toc, –table-of-contents

使用该参数后,会在输出文档开头自动产生文件目录,对于输出格式是man, docbook, slidy, slideous, s5, docx 或者odt的文档,该参数不起任何作用。

  • –toc-depth=NUMBER

指定文件目录中包含的章节级别,默认NUMBER=3,表示一级标题、二级标题、三级标题都会被在目录中展示。

  • -V KEY[=VAL], –variable=KEY[:VAL]

当渲染standalone模式下文档时,设置模板变量KEY的值为VAL。pandoc会自动设置默认模板中的这些变量,因此该选项这通常在使用–template选项指定自定义模板时有用,如果没有指定VAL值,那么该KEY会被赋予值true。

  • -s, –standalone

转换输出文档时会自动加上合适的header和footer(例如standalone HTML, LaTeX, RTF).该选择在转换输出pdf,epub,epub3,fb2,docx,odt格式文件时会被自动设置,因此如果转换输出上述格式文件,则不用显示指定该选项。

  • -N, –number-sections

对于转换输出LaTeX, ConTeXt, HTML, EPUB格式文档时,对文中章节进行编号。默认情况下,文章的章节是不会被编号的。对于使用了class unnumbered 的章节肯定不会被标号,即使使用了–number-sections选项。

五、命令备忘

pandoc --pdf-engine=xelatex -V mainfont='WenQuanYi Zen Hei Mono' 1.md --template pm -o 2.pdf

我用了这个模版,对中文比较友好,将 pm-template.latex 文件拷贝到 /usr/share/pandoc/data/templates后直接使用。

这个模版需要做些调整,将字体设置的地方LiHei Pro,改为我本机存在的字体WenQuanYi Zen Hei Mono

遇到个问题,中文无法换行。最后直接用这个模版解决了。

还有另一个模版Eisvogel也比较常用的。

参考资料


Nginx 缓存 DNS 解析问题

我使用了容器化的oprenresty,一般都会使用 upstream 特性转发到多个后端。因为是高可用的架构,后端偶尔也会手动重启服务。但问题在于 nginx 原生不支持动态解析 dns,需要做额外的模块编译。这篇文章记录我手动编译 openresty 容器的过程。

一、缓存问题的解决方案

1 每次更改 DNS 解析都重载 Nginx

重载 Nginx 一定会刷新缓存。

2 使用 Nginx 的 resolver

我们在使用 Nginx 过程中,有时需要根据 Url 传值动态选择 host 进行代理转发,这种模式下,一开始是不会去进行 DNS 解析的,只有请求的时候才会进行 DNS 解析,并且要设置 resolver 指定 DNS 服务器 IP。

这个时候,我们就可以使用 resolver 语法来解决 DNS 缓存的问题,比如说,我在原来的 Nginx 配置里指定 DNS IP,并设置缓存 60 秒。

server {
    listen 80;
    server_name www.test.com;

    resolver 127.0.0.1 valid=60s;
    resolver_timeout 3s;

    set $proxy_url "proxy.test.com";
    location / {
        proxy_set_header Host proxy.test.com;
        proxy_pass http://$proxy_url;
    }
}

但这种方法无法作用于 upstream 里的域名。

3 使用模块nginx-upstream-dynamic-servers

模块地址: nginx-upstream-dynamic-servers

该模块在第一次启动的时候会进行一次解析,解析完后,在 DNS 服务器设定的 TTL 过期时间内不会再次更新,过期后会再次发起解析请求

使用方法

http {
  resolver 8.8.8.8;

  upstream example {
    server example.com resolve;
  }
}

使用这种方法的时候,DNS TTL 时间需要设置短一些。

4 使用模块 ngx_upstream_jdomain

文档地址: domain_resolve

ngx_upstream_jdomain 模块是一个依赖 DNS 解析实现的 upstream 负载均衡,该模式下,允许使用域名来写 upstream 后端。该模块默认情况下,会每秒做一次 DNS 解析,使用方法如下

http {
    resolver 8.8.8.8;
    resolver_timeout 10s;

    upstream backend {
        jdomain www.baidu.com port=80 interval=5; # 每 5 秒解析一次
    }
    server {
        listen  8080;
    
        location / {
            proxy_pass http://backend;
        }
    }
}

5 使用其他版本 Nginx

  • Tengine Tengine 的 ngx_http_upstream_dynamic 模块可以提供动态的 DNS 解析
  • NGINX Plus Plus版本提供了动态解析的语法

在这里我才用了第三种方案,使用模块nginx-upstream-dynamic-servers。

二、容器化编译openresty

大致介绍一下注意点:

  1. 自定义编译参考官方文档:https://github.com/openresty/docker-openresty#building-non-rpm-based

  2. 系统我选用了alpine-3.12版本,RESTY版本1.17.8.2

  3. 在RESTY_CONFIG_OPTIONS中增加了自定义的编译命令:

        --add-module=/tmp/nginx-upstream-dynamic-servers-0.4.0 \
    
  4. 增加这个包的下载解压命令:

        && cd /tmp \
        && curl -fSL https://github.com/GUI/nginx-upstream-dynamic-servers/archive/refs/tags/v0.4.0.tar.gz -o  nginx-upstream-dynamic-servers.v0.4.0.tar.gz \
        && tar zxvf nginx-upstream-dynamic-servers.v0.4.0.tar.gz \
    
  5. 修改了一些其他组件的下载地址,有些链接失效了,例如pcre:

    curl -fSL https://ftp.exim.org/pub/pcre/pcre-${RESTY_PCRE_VERSION}.tar.gz -o pcre-${RESTY_PCRE_VERSION}.tar.gz
    
  6. 注意编译最后一步要把下载的东西给清空了,节省空间

编译文件下载。编译文件夹内容如下:

image-20220304121133258

具体dockerfile如下:

# Dockerfile - alpine
# https://github.com/openresty/docker-openresty

ARG RESTY_IMAGE_BASE="alpine"
ARG RESTY_IMAGE_TAG="3.12"

FROM ${RESTY_IMAGE_BASE}:${RESTY_IMAGE_TAG}

LABEL maintainer="Evan Wies <evan@neomantra.net>"

# Docker Build Arguments
ARG RESTY_IMAGE_BASE="alpine"
ARG RESTY_IMAGE_TAG="3.12"
ARG RESTY_VERSION="1.17.8.2"
ARG RESTY_OPENSSL_VERSION="1.1.1g"
ARG RESTY_OPENSSL_PATCH_VERSION="1.1.1f"
ARG RESTY_OPENSSL_URL_BASE="https://www.openssl.org/source"
ARG RESTY_PCRE_VERSION="8.44"
ARG RESTY_VTS_VERSION="0.1.18"
ARG RESTY_J="1"
ARG RESTY_CONFIG_OPTIONS="\
    --with-compat \
    --with-file-aio \
    --with-http_addition_module \
    --with-http_auth_request_module \
    --with-http_dav_module \
    --with-http_flv_module \
    --with-http_geoip_module=dynamic \
    --with-http_gunzip_module \
    --with-http_gzip_static_module \
    --with-http_image_filter_module=dynamic \
    --with-http_mp4_module \
    --with-http_random_index_module \
    --with-http_realip_module \
    --with-http_secure_link_module \
    --with-http_slice_module \
    --with-http_ssl_module \
    --with-http_stub_status_module \
    --with-http_sub_module \
    --with-http_v2_module \
    --with-http_xslt_module=dynamic \
    --with-ipv6 \
    --with-mail \
    --with-mail_ssl_module \
    --with-md5-asm \
    --with-pcre-jit \
    --with-sha1-asm \
    --with-stream \
    --with-stream_ssl_module \
    --with-threads \
    --add-module=/tmp/nginx-module-vts-0.1.18 \
    --add-module=/tmp/nginx-upstream-dynamic-servers-0.4.0 \
    "
ARG RESTY_CONFIG_OPTIONS_MORE=""
ARG RESTY_LUAJIT_OPTIONS="--with-luajit-xcflags='-DLUAJIT_NUMMODE=2 -DLUAJIT_ENABLE_LUA52COMPAT'"

ARG RESTY_ADD_PACKAGE_BUILDDEPS=""
ARG RESTY_ADD_PACKAGE_RUNDEPS=""
ARG RESTY_EVAL_PRE_CONFIGURE=""
ARG RESTY_EVAL_POST_MAKE=""

# These are not intended to be user-specified
ARG _RESTY_CONFIG_DEPS="--with-pcre \
    --with-cc-opt='-DNGX_LUA_ABORT_AT_PANIC -I/usr/local/openresty/pcre/include -I/usr/local/openresty/openssl/include' \
    --with-ld-opt='-L/usr/local/openresty/pcre/lib -L/usr/local/openresty/openssl/lib -Wl,-rpath,/usr/local/openresty/pcre/lib:/usr/local/openresty/openssl/lib' \
    "

LABEL resty_image_base="${RESTY_IMAGE_BASE}"
LABEL resty_image_tag="${RESTY_IMAGE_TAG}"
LABEL resty_version="${RESTY_VERSION}"
LABEL resty_openssl_version="${RESTY_OPENSSL_VERSION}"
LABEL resty_openssl_patch_version="${RESTY_OPENSSL_PATCH_VERSION}"
LABEL resty_openssl_url_base="${RESTY_OPENSSL_URL_BASE}"
LABEL resty_pcre_version="${RESTY_PCRE_VERSION}"
LABEL resty_config_options="${RESTY_CONFIG_OPTIONS}"
LABEL resty_config_options_more="${RESTY_CONFIG_OPTIONS_MORE}"
LABEL resty_config_deps="${_RESTY_CONFIG_DEPS}"
LABEL resty_add_package_builddeps="${RESTY_ADD_PACKAGE_BUILDDEPS}"
LABEL resty_add_package_rundeps="${RESTY_ADD_PACKAGE_RUNDEPS}"
LABEL resty_eval_pre_configure="${RESTY_EVAL_PRE_CONFIGURE}"
LABEL resty_eval_post_make="${RESTY_EVAL_POST_MAKE}"

RUN apk add --no-cache --virtual .build-deps \
        build-base \
        coreutils \
        curl \
        gd-dev \
        geoip-dev \
        libxslt-dev \
        linux-headers \
        make \
        perl-dev \
        readline-dev \
        zlib-dev \
        ${RESTY_ADD_PACKAGE_BUILDDEPS} \
    && apk add --no-cache \
        gd \
        geoip \
        libgcc \
        libxslt \
        zlib \
        ${RESTY_ADD_PACKAGE_RUNDEPS} \
    && cd /tmp \
    && if [ -n "${RESTY_EVAL_PRE_CONFIGURE}" ]; then eval $(echo ${RESTY_EVAL_PRE_CONFIGURE}); fi \
    && cd /tmp \
    && curl -fSL https://github.com/GUI/nginx-upstream-dynamic-servers/archive/refs/tags/v0.4.0.tar.gz -o  nginx-upstream-dynamic-servers.v0.4.0.tar.gz \
    && tar zxvf nginx-upstream-dynamic-servers.v0.4.0.tar.gz \
    && cd /tmp \
    && curl -fSL https://github.com/vozlt/nginx-module-vts/archive/v${RESTY_VTS_VERSION}.tar.gz -o  nginx-module-vts-${RESTY_VTS_VERSION}.tar.gz \
    && tar xzf nginx-module-vts-${RESTY_VTS_VERSION}.tar.gz \
    && cd /tmp \
    && curl -fSL https://github.com/vozlt/nginx-module-vts/archive/v${RESTY_VTS_VERSION}.tar.gz -o  nginx-module-vts-${RESTY_VTS_VERSION}.tar.gz \
    && tar xzf nginx-module-vts-${RESTY_VTS_VERSION}.tar.gz \
    && curl -fSL "${RESTY_OPENSSL_URL_BASE}/openssl-${RESTY_OPENSSL_VERSION}.tar.gz" -o openssl-${RESTY_OPENSSL_VERSION}.tar.gz \
    && tar xzf openssl-${RESTY_OPENSSL_VERSION}.tar.gz \
    && cd openssl-${RESTY_OPENSSL_VERSION} \
    && if [ $(echo ${RESTY_OPENSSL_VERSION} | cut -c 1-5) = "1.1.1" ] ; then \
        echo 'patching OpenSSL 1.1.1 for OpenResty' \
        && curl -s https://raw.githubusercontent.com/openresty/openresty/master/patches/openssl-${RESTY_OPENSSL_PATCH_VERSION}-sess_set_get_cb_yield.patch | patch -p1 ; \
    fi \
    && if [ $(echo ${RESTY_OPENSSL_VERSION} | cut -c 1-5) = "1.1.0" ] ; then \
        echo 'patching OpenSSL 1.1.0 for OpenResty' \
        && curl -s https://raw.githubusercontent.com/openresty/openresty/ed328977028c3ec3033bc25873ee360056e247cd/patches/openssl-1.1.0j-parallel_build_fix.patch | patch -p1 \
        && curl -s https://raw.githubusercontent.com/openresty/openresty/master/patches/openssl-${RESTY_OPENSSL_PATCH_VERSION}-sess_set_get_cb_yield.patch | patch -p1 ; \
    fi \
    && ./config \
      no-threads shared zlib -g \
      enable-ssl3 enable-ssl3-method \
      --prefix=/usr/local/openresty/openssl \
      --libdir=lib \
      -Wl,-rpath,/usr/local/openresty/openssl/lib \
    && make -j${RESTY_J} \
    && make -j${RESTY_J} install_sw \
    && cd /tmp \
    && curl -fSL https://ftp.exim.org/pub/pcre/pcre-${RESTY_PCRE_VERSION}.tar.gz -o pcre-${RESTY_PCRE_VERSION}.tar.gz \
    && tar xzf pcre-${RESTY_PCRE_VERSION}.tar.gz \
    && cd /tmp/pcre-${RESTY_PCRE_VERSION} \
    && ./configure \
        --prefix=/usr/local/openresty/pcre \
        --disable-cpp \
        --enable-jit \
        --enable-utf \
        --enable-unicode-properties \
    && make -j${RESTY_J} \
    && make -j${RESTY_J} install \
    && cd /tmp \
    && curl -fSL https://openresty.org/download/openresty-${RESTY_VERSION}.tar.gz -o openresty-${RESTY_VERSION}.tar.gz \
    && tar xzf openresty-${RESTY_VERSION}.tar.gz \
    && cd /tmp/openresty-${RESTY_VERSION} \
    && eval ./configure -j${RESTY_J} ${_RESTY_CONFIG_DEPS} ${RESTY_CONFIG_OPTIONS} ${RESTY_CONFIG_OPTIONS_MORE} ${RESTY_LUAJIT_OPTIONS} \
    && make -j${RESTY_J} \
    && make -j${RESTY_J} install \
    && cd /tmp \
    && if [ -n "${RESTY_EVAL_POST_MAKE}" ]; then eval $(echo ${RESTY_EVAL_POST_MAKE}); fi \
    && rm -rf \
        nginx-module-vts-${RESTY_VTS_VERSION}.tar.gz nginx-module-vts-${RESTY_VTS_VERSION} \
        openssl-${RESTY_OPENSSL_VERSION}.tar.gz openssl-${RESTY_OPENSSL_VERSION} \
        pcre-${RESTY_PCRE_VERSION}.tar.gz pcre-${RESTY_PCRE_VERSION} \
        openresty-${RESTY_VERSION}.tar.gz openresty-${RESTY_VERSION} \
        * \
    && apk del .build-deps \
    && mkdir -p /var/run/openresty \
    && ln -sf /dev/stdout /usr/local/openresty/nginx/logs/access.log \
    && ln -sf /dev/stderr /usr/local/openresty/nginx/logs/error.log

# Add additional binaries into PATH for convenience
ENV PATH=$PATH:/usr/local/openresty/luajit/bin:/usr/local/openresty/nginx/sbin:/usr/local/openresty/bin

# Copy nginx configuration files
COPY nginx.conf /usr/local/openresty/nginx/conf/nginx.conf
COPY nginx.vh.default.conf /etc/nginx/conf.d/default.conf

CMD ["/usr/local/openresty/bin/openresty", "-g", "daemon off;"]

# Use SIGQUIT instead of default SIGTERM to cleanly drain requests
# See https://github.com/openresty/docker-openresty/blob/master/README.md#tips--pitfalls
STOPSIGNAL SIGQUIT

编译命令:

docker build -t kelvinblood/openresty:v3.12.1 .

参考资料