使用代理进行 docker build 问题的解决思路

问题描述 在使用 docker build 打包镜像时,遇到了需要使用代理访问网络的需求。使用如下的 Dockerfile 来模拟这个场景: FROM golang:1.12 RUN curl www.google.com --max-time 3 国内一般网络环境下,curl www.google.com 是无法正常返回的,加入 –max-time 让 curl 的耗时不要太长。 配置 http_proxy 变量 首先需要在环境变量中设置 http_proxy 和 https_proxy,使得访问网络的命令(这里使用 curl 来代表)能够通过环境变量中配置的代理服务器访问 www.google.com。 docker build 命令虽然是在 docker 所在的宿主机上执行的,看上去像是直接使用了宿主机的网络环境,但实际上 docker build 也是启动了一个 container 进行构建,所以在构建过程中的所有命令都是在 container 中执行的,http_proxy 和 https_proxy 的配置也应该是在 container 中进行的。可以使用 ENV 来配置 container 中的环境变量。 代理服务器启动在宿主机的 1087 端口上,修改 dockerfile 文件: FROM golang:1.12 ENV http_proxy "http://127.0.0.1:1087" ENV HTTP_PROXY "http://127.0.0.1:1087" ENV https_proxy "http://127.0.0.1:1087" ENV HTTPS_PROXY "http://127.0.0.1:1087" RUN curl www.google.com --max-time 3 重新执行 docker build 会发现 curl 依旧无法访问 www.google.com,从报错信息上可以看到 127.0.0.1 上的 1087 端口上并没有服务。 ...

四月 18, 2019 · 1 分钟 · Zhiya

理解 PostgreSQL 的 count 函数的行为

关于 count 函数的使用一直存在争议,尤其是在 MySQL 中,作为流行度越来越高的 PostgreSQL 是否也有类似的问题呢,我们通过实践来理解一下 PostgreSQL 中 count 函数的行为。 构建测试数据库 创建测试数据库,并创建测试表。测试表中有自增 ID、创建时间、内容三个字段,自增 ID 字段是主键。 create database performance_test; create table test_tbl (id serial primary key, created_at timestamp, content varchar(512)); 生成测试数据 使用 generate_series 函数生成自增 ID,使用 now() 函数生成 created_at 列,对于 content 列,使用了 repeat(md5(random()::text), 10) 生成 10 个 32 位长度的 md5 字符串。使用下列语句,插入 1000w 条记录用于测试。 performance_test=# insert into test_tbl select generate_series(1,10000000),now(),repeat(md5(random()::text),10); INSERT 0 10000000 Time: 212184.223 ms (03:32.184) 由 count 语句引发的思考 默认情况下 PostgreSQL 不开启 SQL 执行时间的显示,所以需要手动开启一下,方便后面的测试对比。 \timing on count(*) 和 count(1) 的性能区别是经常被讨论的问题,分别使用 count(*) 和 count(1) 执行一次查询。 ...

四月 16, 2019 · 5 分钟 · Zhiya

JWT 避坑指南:nbf 验签失效问题的解决

现象 刚签发的 JWT,在下一个请求使用时候会失效,请求会报 422 错误。 { "msg": "The token is not yet valid (nbf)" } 如果隔几秒再请求(例如使用 Chrome 开发者工具中的 Replay XHR),就会成功。 nbf 字段的原理 查看上面的报错信息,会发现有一个 nbf,nbf 是 JWT 协议中的一个字段,是 Not Before 的缩写,表示 JWT Token 在这个时间之前是无效的,一般来讲会设置成签发的时间。这里产生了一个猜想,多服务器环境时候,服务器之间时间如果不一致,一台服务器签发的 token 如果立刻被发往另一台服务器验证,就很容易产生 nbf 字段验证不通过的问题。其实 JWT 协议已经考虑到了这类问题,所以协议中在 nbf 这一节专门提到了可以使用一个 small leeway 来解决这个问题。 4.1.5. “nbf” (Not Before) Claim The “nbf” (not before) claim identifies the time before which the JWT MUST NOT be accepted for processing. The processing of the “nbf” claim requires that the current date/time MUST be after or equal to the not-before date/time listed in the “nbf” claim. Implementers MAY provide for some small leeway, usually no more than a few minutes, to account for clock skew. Its value MUST be a number containing a NumericDate value. Use of this claim is OPTIONAL. ...

三月 26, 2019 · 2 分钟 · Zhiya

nginx + ingress + gunicorn 环境上传大文件报错问题的解决思路

在基于 Kubernetes 部署,使用 Gunicorn 运行的 Python Web 应用中,上传大文件时出现了一系列的错误,现在将解决问题的思路记录如下。 文件上传过程 上传文件流程 上传的文件首先到达 Kubernetes 所在的宿主机。 宿主机上的 Nginx 通过 Proxy 转发给 Kubernetes 集群中的 Ingress Controller,Ingress controller 也是使用 Nginx 实现的。 Ingress Controller 中的 Nginx 通过 Proxy 转发给 Gunicorn。 Gunicorn 会启动若干个 Worker 处理请求,所以 Gunicorn 会再转发给 Worker。 Worker 就是最终的 Python Web App 错误 413 的解决 首先碰到的是 413 Request Entity Too Large 错误,在上传过程中连接被中断(基本上每次都是相同的上传百分比被中断),请求返回 413,首先考虑到 Nginx 对于请求体的大小有限制,查看 Nginx 文档,发现 client_max_body_size 参数控制请求体的大小,默认的设置是 1mb。 client_max_body_size: Sets the maximum allowed size of the client request body, specified in the “Content-Length” request header field. If the size in a request exceeds the configured value, the 413 (Request Entity Too Large) error is returned to the client. Please be aware that browsers cannot correctly display this error. Setting size to 0 disables checking of client request body size. ...

二月 28, 2019 · 3 分钟 · Zhiya

Python 日志库 logging 的理解和实践经验

本文从 Python logging 库的基础概念入手,理解 logging 库的执行流程,以及可能忽视的一些细节。 日志级别 logging 库预置了 5 个错误级别,还有一个 NOTSET 级别,作为 logger 的默认值。 CRITICAL = 50 ERROR = 40 WARNING = 30 INFO = 20 DEBUG = 10 NOTSET = 0 logging 库也支持自定义错误级别,通过上面的源码可以看到,在不同级别的错误中间预留了 10 个数字的位置,方便我们在预置错误级别的基础上添加更细致的错误级别。 import logging logging.addLevelName(31, 'SERIOUS WARNING') logger = logging.getLogger('log') logger.warn('warn info') logger.log(logging.getLevelName('SERIOUS_WARNING'), 'serious warn') 例如添加一个 SERIOUS WARNING 类型的错误,值为 31,就可以用 log 方法输出该级别的错误。 也可以覆盖 logging 预置的错误级别,例如将 WARNING 修改为 SERIOUS WARNING。 logging.addLevelName(30, 'SERIOUS WARNING') logger = logging.getLogger('log') print(logging.getLevelName(30)) # SERIOUS WARNING LogRecord、Formatter logging 库中的每一条 log 都以 LogRecord 的形式存在,当调用 logger 打印 log 时候,都会有一条 LogRecord 被自动创建出来,LogRecord 中包含了大量的和该条日志相关的属性,也包含用户传入的 message。 ...

一月 25, 2019 · 3 分钟 · Zhiya