Skip to content

Commit ba519f4

Browse files
committed
update
1 parent 7c21b7d commit ba519f4

12 files changed

+257
-6
lines changed

README.md

+9
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ See the [LICENSE][] file for the specific language governing permissions and lim
107107

108108
## Docker
109109

110+
- [Alpine 镜像](docker/alpine.md)
110111
- [device or resource busy](docker/device-or-resource-busy.md)
111112
- [docker-compose 启动容器顺序](docker/docker-compose-startup-order.md)
112113
- [进入 docker for mac 的虚拟机](docker/docker-for-mac-tty.md)
@@ -274,13 +275,16 @@ See the [LICENSE][] file for the specific language governing permissions and lim
274275
- [rsync 与 scp](linux/rsync-and-scp.md)
275276
- [在 alpine 中找不到 setup-apkcache 等 setup-* 命令](linux/setup-scripts-in-alpine.md)
276277
- [shebang](linux/shebang.md)
278+
- [共享内存](linux/shm.md)
277279
- [拆分与合并文件](linux/split-and-merge-file.md)
278280
- [SSH](linux/ssh.md)
279281
- [strace](linux/strace.md)
280282
- [sudo and su](linux/sudo-and-su.md)
281283
- [Linux 系统调用](linux/system-call.md)
282284
- [systemd](linux/systemd.md)
283285
- [tailf](linux/tailf.md)
286+
- [基于内存的虚拟文件系统](linux/temporary-fs-in-memory.md)
287+
- [UNIX Domain Socket](linux/unix-domain-socket.md)
284288
- [unlink 是删除任何文件](linux/unlink.md)
285289
- [/usr/bin/env](linux/usr-bin-env.md)
286290
- [奇怪的 ESC](linux/weird-esc-key.md)
@@ -308,6 +312,8 @@ See the [LICENSE][] file for the specific language governing permissions and lim
308312
## 网络
309313

310314
- [DNS SRV](network/dns_srv.md)
315+
- [HTTP Request/Response 网络包](network/http-request-and-response-package.md)
316+
- [TCP Buffer 大小](network/tcp-buffer-size.md)
311317

312318
## Nodejs
313319

@@ -384,6 +390,9 @@ See the [LICENSE][] file for the specific language governing permissions and lim
384390
## Python
385391

386392
- [python 环境配置](python/environment.md)
393+
- [pycache](python/pycache.md)
394+
- [Python Dockerfile](python/python-dockerfile.md)
395+
- [Python Virtualenv](python/virtualenv.md)
387396

388397
## Racket
389398

docker/alpine.md

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
## Alpine 镜像
2+
3+
### apk
4+
5+
- `apk add --no-cache <pkg-name>` 不留缓存安装
6+
7+
### 常用包
8+
9+
搜索: https://pkgs.alpinelinux.org/packages
10+
11+
`build-essential` 类似的包,提供编译工具。`alpine-sdk``build-base`。参考这个 [issue](https://github.com/gliderlabs/docker-alpine/issues/24)
12+
13+
`apk add binutils`

docker/dockerfile.md

+5
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,8 @@ CMD ["/home/user/bin/xxx"]
2525
等价于 `bash -c /home/user/bin/xxx`
2626

2727
这样编译出来的镜像,可以用 `docker run -it <image> bash` 方便进入 shell 进行调试。
28+
29+
### 默认 SHELL
30+
31+
在执行 RUN 时,默认 shell 是 sh 而不是 bash。这会导致无法使用 `source` 等 bash 内置命令。
32+
所以可以使用 `SHELL ["/bin/bash", "--login", "-c"]` 来修改 Dockerfile 执行时的 SHELL。[参考链接](https://docs.docker.com/engine/reference/builder/#shell)

linux/shm.md

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
## 共享内存
2+
3+
共享内存有两种方式,
4+
5+
- POSIX 共享内存: mmap、shm_open、shm_unlink
6+
- System V 共享内存: shmget、shmat、shmdt、shmctl
7+
8+
必读
9+
10+
- [认真分析mmap:是什么 为什么 怎么用](https://www.cnblogs.com/huxiao-tee/p/4660352.html)
11+
- [从内核文件系统看文件读写过程](https://www.cnblogs.com/huxiao-tee/p/4657851.html)
12+
13+
## mmap
14+
15+
mmap 是将文件映射到进程的虚拟空间。
16+
17+
mmap 要和基于内存的文件系统(例如 tmpfs)配合,才能做到最高效的数据传输。
18+
19+
### mmap on socket
20+
21+
> mmap() facility available with the PACKET socket interface on 2.4/2.6/3.x kernels
22+
23+
https://www.kernel.org/doc/Documentation/networking/packet_mmap.txt

linux/temporary-fs-in-memory.md

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
## 基于内存的虚拟文件系统
2+
3+
tmpfs、ramfs、RamDisk
4+
5+
### tmpfs
6+
7+
/dev/shm
8+
9+
http://www.361way.com/dev-shm/4029.html

linux/unix-domain-socket.md

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
## UNIX Domain Socket
2+
3+
UNIX Domain Socket 简称 UDS,又叫 IPC Socket。是一种进程间通信的方法。
4+
5+
UDS 是 POSIX 操作系统的标准组件。
6+
7+
三种类型:
8+
9+
- SOCK_STREAM (compare to TCP) – for a stream-oriented socket
10+
- SOCK_DGRAM (compare to UDP) – for a datagram-oriented socket that preserves message boundaries (as on most UNIX implementations, UNIX domain datagram sockets are always reliable and don't reorder datagrams)
11+
- SOCK_SEQPACKET (compare to SCTP) – for a sequenced-packet socket that is connection-oriented, preserves message boundaries, and delivers messages in the order that they were sent
12+
13+
14+
[这篇文章](https://eli.thegreenplace.net/2019/unix-domain-sockets-in-go/) 的 Benchmarking UDS compared to loop-back TCP sockets。
15+
16+
[unix domain sockets vs. internet sockets](https://lists.freebsd.org/pipermail/freebsd-performance/2005-February/001143.html)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
## HTTP Request/Response 网络包
2+
3+
Q: 多个 http 请求可以复用同一个 tcp 连接,那么程序怎么知道它得到的 http response 包是对应它之前发出的哪个 http request 包?
4+
5+
A: http 1.1 虽然是复用同一个 tcp 连接,但是按顺序收发的,意味着会阻塞。所以 http 1.1 的报文结构没有 ID 之类的字段。所以在浏览器对于 http 1.1 会建立多个 tcp 连接,来保证并发 http 请求。
6+
在 http 2 才有多路复用,利用 Stream ID 来标志的,真正复用同一个 tcp 连接并发 http 请求。https://tools.ietf.org/html/rfc7540#page-21

network/tcp-buffer-size.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
## TCP Buffer 大小
2+
3+
Q: HTTP 1.1 协议里没有对 POST Body 的长度进行限制。HTTP 基于 TCP 的,TCP 包的 MSS 最大就 1460 字节(约 1.43 KiB)。那么当我发送一个 HTTP POST 请求,body 是 1 MiB 大小的数据。网络包的拆包和重组的过程是由谁主动控制的,HTTP 还是 TCP ?
4+
如果是 TCP 负责拆包和重组,那么 TCP 怎么知道何时应该把 buffer 传给应用层处理?比如接收到 500KiB,但完整的 http 包有 1MiB。
5+
6+
A: TCP 滑动窗口的大小一般为 64 KiB,调整 TCP 滑动窗口因子,窗口大小最大可到 1GiB。

python/environment.md

+14-6
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,16 @@ pip 路径注意:
1515
- pip install
1616
- pip install --user
1717

18-
### Python 多版本安装和管理
18+
### 版本管理器 pyenv
1919

2020
一般来说 [pyenv][] 的用户是 python 开发者。一般用户只要用系统包管理器装 python2 和 python3 就够了,因为 python 版本比较稳定,没必要用 pyenv。
2121

22-
### 虚拟环境
23-
24-
https://zhuanlan.zhihu.com/p/81568689
22+
- 执行 `pyenv install 3.8.2` 安装指定版本。
23+
- 执行 `pyenv shell 3.8.2` 把当前 shell 切换到指定版本。
2524

26-
如果你使用 Python 2,那就只能选择 [virtualenv][],你需要额外安装它。
25+
### 虚拟环境
2726

28-
[venv][][virtualenv][] 的子集,从 Python 3.3 起,被集成到 Python 标准库中。意味着 Python 3.2 以下的都用不来 venv。且 venv 有缺点,详见 [virtualenv][] 文档。总结,直接用 virtualenv
27+
详见 [./virtualenv.md](./virtualenv.md)
2928

3029
### pipx
3130

@@ -45,6 +44,15 @@ https://zhuanlan.zhihu.com/p/81568689
4544
- https://stackoverflow.com/a/42989020/4622308
4645
- https://stackoverflow.com/a/54065289/4622308
4746

47+
48+
#### 生成依赖清单
49+
50+
`pip freeze > requirements.txt`
51+
52+
### 包管理器 Pipenv
53+
54+
[Pipenv](https://pipenv-fork.readthedocs.io/en/latest/)
55+
4856
### 参考文章
4957

5058
- [The right and wrong way to set Python 3 as default on a Mac](https://opensource.com/article/19/5/python-3-default-mac)

python/pycache.md

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
## pycache
2+
3+
### __pycache__
4+
5+
### .pyc 文件包含当前项目的路径
6+
7+
发现 pyc 文件里会包含当前项目的路径,并不是每个文件都有这种现象,只有少部分有。比如 etcd3 和 yaml 这两个包里是有的。
8+
9+
找了一下发现是用来做 traceback 的,不影响代码逻辑。
10+
详见 https://stackoverflow.com/questions/11191680/why-do-python-pyc-files-contain-the-absolute-path-of-their-source-code

python/python-dockerfile.md

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
## Python Dockerfile
2+
3+
### 不要使用 Alpine 镜像
4+
5+
不要使用 Alpine 镜像,因为 [Using Alpine can make Python Docker builds 50× slower](https://pythonspeed.com/articles/alpine-docker-python)
6+
[编译 grpc 时很慢](https://github.com/grpc/grpc/issues/20493),一直提示 `Building wheel for grpcio (setup.py): still running...` 等了很久才编译完。
7+
这个 [issue](https://github.com/grpc/grpc/issues/11125) 说是 `manylinux1` 导致的问题。[解决方案](https://github.com/pypa/pip/issues/3969#issuecomment-247381915)没看懂。
8+
9+
### glibc 与 musl
10+
11+
Alpine 系统里编译代码使用的不是 glibc 而是 musl,就会导致编译出来的包依赖动态链接库 ld-musl-x86_64.so.1。
12+
如果部署系统上没有它,会报错 `/lib/ld-musl-x86_64.so.1: bad ELF interpreter: No such file or directory`
13+
14+
参考[链接](https://cloud.tencent.com/developer/article/1536308)

python/virtualenv.md

+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
## Python Virtualenv
2+
3+
https://zhuanlan.zhihu.com/p/81568689
4+
5+
如果你使用 Python 2,那就只能选择 [virtualenv][],你需要额外安装它。
6+
7+
[venv][][virtualenv][] 的子集,从 Python 3.3 起,被集成到 Python 标准库中。意味着 Python 3.2 以下的都用不来 venv。且 venv 有缺点,详见 [virtualenv][] 文档。
8+
9+
- `python -m venv venv` 会创建 venv 目录,默认是把 venv/bin/ 里面的文件都是软链接,指向全局环境的 python。
10+
- `python -m venv --copies venv` 会创建 venv 目录,`--copies` 把全局环境的 python 全都拷贝到 venv 目录里。
11+
- `virtualenv -p ~/.pyenv/versions/3.8.2/bin/python --copies venv` virtualenv 可以用 `-p` 指定拷贝哪个路径下的 python。
12+
13+
### virtualenv 没有打包动态链接库
14+
15+
virtualenv 和 python 3 的 venv 都有这问题。
16+
17+
https://github.com/pypa/virtualenv/issues/1015
18+
https://github.com/pypa/virtualenv/pull/1045
19+
20+
执行 `ldd /usr/local/bin/python` 看 python 依赖哪些动态链接库。
21+
22+
如果目标部署机器上没有对应的动态链接库,首先要把动态链接库拷贝到部署机任意位置(通常是 `/usr/local/lib/`)。然后在 LD_LIBRARY_PATH 加入目录路径即可。例如 `export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib`
23+
24+
### virtualenv 没有打包 /usr/local/lib/python3.5
25+
26+
这里 python3.5 只是个例子,跟 python 具体版本没关系。
27+
28+
```
29+
$ python
30+
Could not find platform independent libraries <prefix>
31+
Could not find platform dependent libraries <exec_prefix>
32+
Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]
33+
Fatal Python error: Py_Initialize: Unable to get the locale encoding
34+
ImportError: No module named 'encodings'
35+
36+
Current thread 0x00007f4dffee0740 (most recent call first):
37+
Aborted (core dumped)
38+
```
39+
40+
encodings 这种 python 标准库,都在 /usr/local/lib/python3.5 路径下。
41+
42+
43+
### 制作完整的 venv 离线包
44+
45+
两种方式,
46+
47+
1. 从官方 docker 镜像中制作 venv,安装 python 依赖包。
48+
2. 自己编译 python,制作 venv,安装 python 依赖包。这种情况适用于 venv 拷贝到(跟镜像同一基线的)宿主机上。
49+
50+
#### 方案 1
51+
52+
```Dockerfile
53+
FROM python:3.8.2-slim
54+
55+
WORKDIR /app
56+
57+
SHELL ["/bin/bash", "-c"]
58+
59+
RUN apt-get update
60+
RUN apt-get install -y build-essential
61+
RUN python -m venv --copies venv
62+
RUN mkdir -p venv/dll && \
63+
cp /usr/local/lib/{libpython3.8m.so,libpython3.8m.so.1.0,libpython3.so} venv/dll/ && \
64+
cp -rf /usr/local/lib/python3.8/* venv/lib/python3.8/
65+
66+
ADD requirements.txt .
67+
68+
RUN source ./venv/bin/activate && \
69+
pip install --upgrade pip && \
70+
pip install --no-cache-dir -r ./requirements.txt
71+
RUN tar -czf ./venv.tgz -C ./venv .
72+
73+
CMD [ "bash" ]
74+
```
75+
76+
#### 方案 2
77+
78+
```Dockerfile
79+
FROM centos:7
80+
81+
WORKDIR /app
82+
83+
SHELL ["/bin/bash", "-c"]
84+
85+
# See https://github.com/pyenv/pyenv/wiki/Common-build-problems
86+
RUN yum install -y @development \
87+
zlib-devel bzip2 bzip2-devel readline-devel \
88+
sqlite sqlite-devel openssl-devel xz xz-devel libffi-devel findutils
89+
90+
RUN curl https://pyenv.run | bash
91+
RUN export PATH="/root/.pyenv/bin:$PATH" &&\
92+
eval "$(pyenv init -)" &&\
93+
eval "$(pyenv virtualenv-init -)" &&\
94+
CFLAGS=-I/usr/include/openssl LDFLAGS=-L/usr/lib64 pyenv install -v 3.8.2
95+
96+
RUN export PATH="/root/.pyenv/bin:$PATH" &&\
97+
eval "$(pyenv init -)" &&\
98+
eval "$(pyenv virtualenv-init -)" &&\
99+
pyenv shell 3.8.2 &&\
100+
python -m venv --copies venv
101+
102+
RUN mkdir -p venv/dll && \
103+
cp /root/.pyenv/versions/3.8.2/lib/{libpython3.8m.so,libpython3.8m.so.1.0,libpython3.so} venv/dll/ && \
104+
cp -rf /root/.pyenv/versions/3.8.2/lib/python3.8/* venv/lib/python3.8/
105+
106+
RUN source ./venv/bin/activate && \
107+
pip install --upgrade pip
108+
109+
ADD requirements.txt .
110+
RUN source ./venv/bin/activate && \
111+
pip install -r ./requirements.txt
112+
113+
RUN tar -czf ./venv.tgz -C ./venv .
114+
115+
CMD [ "bash" ]
116+
```
117+
118+
#### docker cp 导出 venv 包
119+
120+
```sh
121+
main() {
122+
local image=$1
123+
local venv_file=$2
124+
125+
local cid
126+
cid=$(docker create "$image")
127+
docker cp "$cid":/app/venv.tgz "$venv_file"
128+
docker rm "$cid"
129+
130+
# tar -xzf "$venv_file" -C "$output"
131+
}
132+
```

0 commit comments

Comments
 (0)