使用 Docker 和 Nginx 打造高性能的二維碼服務
本文將演示如何使用 Docker 完整打造一個基于 Nginx 的高性能二維碼服務,以及對整個服務鏡像進行優化的方法,如果你的網路狀況良好,完整操作和體驗時間應不超過 15 分鐘,
動手前的腦洞
最近有一個小需求,需要在頁面中快速生成一些二維碼,
說到生成二維碼,方法很多,比如按照 QRCode 演算法進行計算之后:
-
使用各種服務端語言,然后呼叫
GD繪圖庫在語言中的API進行繪制,并生成圖片,然后配合能夠提供HTTP服務的軟體對用戶提供圖片訪問地址, -
使用服務端語言,然后使用
CSS和HTML生成可以識別的頁面圖案,然后配合能夠提供HTTP服務的軟體對用戶提供圖片訪問地址, -
使用客戶端腳本,使用
Canvas生成二維碼圖片,或者和上一個方案一樣,生成DOM圖案, -
…
但是只是為了一個功能,就去配置一套完整的語言環境,引入一堆三方依賴,總有一種殺雞用牛刀的感覺,并且在資源利用效率上來說,也不是最優解,
而使用客戶端進行生成,現在雖然不存在太多的兼容問題,但是需要額外引入腳本資源,圖片生成效率也相對較慢,
那么有沒有什么環保高效的方案呢?
自然是有的,還是選擇服務端生成,但是扔掉語言運行時,直接使用 Nginx 提供服務,
使用 Nginx 進行二維碼生成
這里可以使用一個現成的開源模塊 ngx_http_qrcode_module ,
它通過將用戶請求引數進行轉換,并呼叫使用 C 實作的二維碼快速生成庫 libqrencode 的 QRcode_encodeString實作二維碼快速生成,在未開啟快取的情況下,測驗平均生成圖片在 10ms 左右,
為了方便大家理解全部的安裝配置程序,我先提供一個“啰嗦”版本的 Dockerfile:
-
FROM ubuntu:18.04 -
-
RUN cat /etc/apt/sources.list | sed -e "s/archive\.ubuntu\.com/mirrors\.aliyun\.com/" | sed -e "s/security\.ubuntu\.com/mirrors\.aliyun\.com/" | tee /etc/apt/sources.list -
RUN apt update && \ -
apt install -y unzip wget -
-
WORKDIR /data -
-
# https://github.com/fukuchi/libqrencode -
RUN apt install -y autoconf automake autotools-dev libtool pkg-config libpng-dev && \ -
cd /data && wget https://github.com/fukuchi/libqrencode/archive/master.zip && unzip master.zip && rm -rf master.zip && \ -
cd libqrencode-master && ./autogen.sh && ./configure && make && make install && ldconfig && \ -
cd .. && rm -rf libqrencode-master -
-
RUN apt install -y libgd-dev -
-
ADD ngx_http_qrcode /data/ngx_http_qrcode -
ADD nginx-1.15.5.tar.gz /data -
ADD nginx.conf /data -
-
RUN apt install -y libpcre3 libpcre3-dev && \ -
cd nginx-1.15.5 && ./configure --add-module=../ngx_http_qrcode/ && \ -
make && make install && mv /data/nginx.conf /usr/local/nginx/conf/nginx.conf && \ -
cd .. && rm -rf ngx_http_qrcode
將上面的檔案保存完畢,接下來我們來配置 Nginx,
-
worker_processes 1; -
-
events { -
worker_connections 1024; -
} -
-
-
http { -
include mime.types; -
default_type application/octet-stream; -
-
sendfile on; -
-
keepalive_timeout 65; -
-
server { -
listen 80; -
server_name localhost; -
-
location / { -
-
set $fg_color 000000; -
set $bg_color FFFFFF; -
set $level 0; -
set $hint 2; -
set $size 300; -
set $margin 80; -
set $version 2; -
set $case 0; -
set $txt "https://soulteary.com"; -
-
if ( $arg_fg_color ){ -
set $fg_color $arg_fg_color; -
} -
if ( $arg_bg_color ){ -
set $bg_color $arg_bg_color; -
} -
if ( $arg_level ){ -
set $level $arg_level; -
} -
if ( $arg_hint ){ -
set $hint $arg_hint; -
} -
if ( $arg_size ){ -
set $size $arg_size; -
} -
if ( $arg_margin ){ -
set $margin $arg_margin; -
} -
if ( $arg_ver ){ -
set $version $arg_ver; -
} -
if ( $arg_case ){ -
set $case $arg_case; -
} -
if ( $arg_txt ){ -
set $txt $arg_txt; -
} -
-
-
qrcode_fg_color $fg_color; -
qrcode_bg_color $bg_color; -
-
qrcode_level $level; -
qrcode_hint $hint; -
qrcode_size $size; -
qrcode_margin $margin; -
qrcode_version $version; -
qrcode_casesensitive $case; -
qrcode_urlencode_txt $txt; -
-
qrcode_gen; -
} -
-
} -
}
將上面的配置保存為 nginx.conf,然后使用下面的命令進行鏡像構建,
-
docker build -t docker.lab.com/qrcode.lab.com .
如果你的網路通暢,5分鐘之內,這個鏡像就構建完畢了,接下來,我們對它進行一下可用性驗證,
將下面的組態檔保存為 docker-compose.yml,然后使用 docker-compose up 命令啟動,一個支持 HTTP/HTTPS,域名為 qrcode.lab.com 的網站就準備就緒了,
這里我使用了 Traefik 進行服務發現,感興趣的童鞋可以參考我以前寫的文章: 使用服務發現改善開發體驗 、 更完善的 Docker + Traefik 使用方案 、使用 Traefik 的一些補充細節),一旦你開始使用并掌握了它,你會發現搭建高可擴展的 Web 服務變的更簡單了,
-
version: '3' -
-
services: -
-
qrcode: -
image: docker.lab.com/qrcode.lab.com:0.0.2 -
expose: -
- 80 -
networks: -
- traefik -
labels: -
- "traefik.enable=true" -
- "traefik.port=80" -
- "traefik.frontend.rule=Host:qrcode.lab.com" -
- "traefik.frontend.entryPoints=http,https" -
-
networks: -
traefik: -
external: true
然后我們在瀏覽器中分別訪問,來驗證二維碼服務是否就緒:
-
https://qrcode.lab.com -
https://qrcode.lab.com/?size=150&margin=20&txt=https%3A%2F%2Fsoulteary.com
看來服務是正常運行的,本文的基礎需求到這里就解決了,并且,為了這個服務能夠更好的被使用,我們可以在書簽中輸入下面的腳本代碼:
-
javascript:(function(){document.location.href='https://qrcode.lab.com/?size=150&txt='+encodeURIComponent(document.location.href);})()
當你點擊書簽的時候,會將當前頁面自動轉換為一個可以掃描的二維碼,
通過整合陳述句優化容器鏡像
雖然上面的內容已經滿足了我們的基礎需求,但是作為一個有追求的開發者,我們不光是要追求執行效率,還要追求儲存效率,
雖然 Nginx 的運行資源占用不多,
-
top - 09:50:29 up 21 days, 19 min, 0 users, load average: 0.03, 0.05, 0.05 -
Tasks: 4 total, 1 running, 3 sleeping, 0 stopped, 0 zombie -
%Cpu(s): 0.3 us, 0.3 sy, 0.0 ni, 99.4 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st -
KiB Mem : 6101684 total, 332268 free, 3649484 used, 2119932 buff/cache -
KiB Swap: 998396 total, 936632 free, 61764 used. 2122020 avail Mem -
-
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND -
8 nobody 20 0 72352 4792 3124 S 0.7 0.1 0:00.02 nginx -
1 root 20 0 70800 4996 4240 S 0.0 0.1 0:00.01 nginx
但是使用 docker images 命令查看鏡像詳情,我們可以看到這個鏡像還是挺大的,有 400+MB,
-
REPOSITORY TAG IMAGE ID CREATED SIZE -
docker.lab.com/qrcode.lab.com 0.0.1 d98376b43ae9 About a minute ago 454MB
這里我們修改一下上面的鏡像 Dockerfile,嘗試重新進行鏡像構建,
-
FROM ubuntu:18.04 -
-
RUN cat /etc/apt/sources.list | sed -e "s/archive\.ubuntu\.com/mirrors\.aliyun\.com/" | sed -e "s/security\.ubuntu\.com/mirrors\.aliyun\.com/" | tee /etc/apt/sources.list -
-
WORKDIR /tmp -
-
RUN apt update && apt install -y unzip wget autoconf automake autotools-dev libtool pkg-config libpng-dev libgd-dev libpcre3 libpcre3-dev && \ -
wget https://nginx.org/download/nginx-1.15.5.tar.gz && tar -zxvf nginx-1.15.5.tar.gz && rm -rf nginx-1.15.5.tar.gz && \ -
wget https://github.com/dcshi/ngx_http_qrcode_module/archive/master.zip && unzip master.zip && mv ngx_http_qrcode_module-master ngx_http_qrcode_module && rm -rf master.zip && \ -
wget https://github.com/fukuchi/libqrencode/archive/master.zip && unzip master.zip && mv libqrencode-master libqrencode && \ -
cd libqrencode && ./autogen.sh && ./configure && make && make install && ldconfig && \ -
cd /tmp/nginx-1.15.5 && ./configure --add-module=../ngx_http_qrcode_module/ && make && make install && \ -
apt remove -y unzip wget autoconf automake autotools-dev libtool pkg-config && \ -
rm -rf /tmp/* && rm -rf /var/cache/ -
-
ADD nginx.conf /usr/local/nginx/conf/nginx.conf -
-
EXPOSE 80 -
-
ENTRYPOINT [ "/usr/local/nginx/sbin/nginx", "-g", "daemon off;" ]
再次構建完畢,我們會發現鏡像只是減少了 35MB,相比較 400MB 多的整體體積,優化部分杯水車薪,
-
REPOSITORY TAG IMAGE ID CREATED SIZE -
docker.lab.com/qrcode.lab.com 0.0.1 a24ffc73121a 1 minutes ago 420MB
那么優化就到此為止了么?顯然不是,
通過優化基礎鏡像來優化容器鏡像
這里我們選擇使用體積更小的 Linux 鏡像, Alpine來進行同樣功能的二維碼服務的容器鏡像,
因為 Alpine 和 Ubuntu 不是一個社區進行維護,所以軟體包很多名稱是不同的,這里我直接提供我已經查找修改完畢的鏡像檔案,
如果你也有類似的需求,需要將不同系統的軟體進行遷移安裝,可以在 https://pkgs.alpinelinux.org/packages 查找你所需要的軟體包的名稱,
-
FROM alpine:3.8 -
-
RUN cat /etc/apk/repositories | sed -e "s/dl-cdn.alpinelinux.org/mirrors.aliyun.com/" | tee /etc/apk/repositories && \ -
apk --update add openssl-dev pcre-dev zlib-dev wget build-base autoconf automake libtool libpng-dev libgd pcre pcre-dev pkgconfig gd-dev && \ -
cd /tmp && \ -
wget https://nginx.org/download/nginx-1.15.5.tar.gz && tar -zxvf nginx-1.15.5.tar.gz && rm -rf nginx-1.15.5.tar.gz && \ -
wget https://github.com/dcshi/ngx_http_qrcode_module/archive/master.zip && unzip master.zip && mv ngx_http_qrcode_module-master ngx_http_qrcode_module && rm -rf master.zip && \ -
wget https://github.com/fukuchi/libqrencode/archive/master.zip && unzip master.zip && mv libqrencode-master libqrencode && \ -
cd libqrencode && ./autogen.sh && ./configure && make && make install && ldconfig || true && \ -
cd /tmp/nginx-1.15.5 && ./configure --add-module=../ngx_http_qrcode_module/ && make && make install && \ -
apk del build-base autoconf automake pkgconfig && \ -
rm -rf /tmp/* && rm -rf /var/cache/apk/* -
-
ADD nginx.conf /usr/local/nginx/conf/nginx.conf -
-
EXPOSE 80 -
-
ENTRYPOINT [ "/usr/local/nginx/sbin/nginx", "-g", "daemon off;" ]
當鏡像打包完畢,我們再次查看鏡像體積,可以看到體積有了明顯的優化效果,
-
REPOSITORY TAG IMAGE ID CREATED SIZE -
docker.lab.com/qrcode.lab.com 0.0.2 d236b96c8950 1 minutes ago 79.1MB
最后
還記得本文標題中的關鍵詞“高性能”嘛,雖說我個人測驗單實體的回應時間都在 10ms 左右,但是如果你真的考慮使用它做對外服務的話,可以使用下面的命令,根據自己情況對節點進行動態擴容,成倍提高服務回應能力,
-
docker-compose scale qrcode=4
或者使用
-
docker-compose up --scale qrcode=2 -d
如果你也是 Traefik 用戶,你將會看到你的實體被成功進行掛載以及流量負載均衡,
另外,為了避免被惡意利用,還需要考慮使用 Nginx / iptable 的 req_limit 等模塊限制訪問頻率,以及適當修改 ngx_http_qrcode_module 生成內容和圖片尺寸的判斷,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/100382.html
標籤:其他
上一篇:一文解讀Docker (轉)
