本文使用「署名 4.0 國際 (CC BY 4.0)」許可協議,歡迎轉載、或從新修改使用,但須要註明來源。 署名 4.0 國際 (CC BY 4.0)html
本文做者: 蘇洋前端
統計字數: 10813字 閱讀時間: 22分鐘閱讀 本文連接: soulteary.com/2018/08/28/…linux
在踩坑無數以後,屢次修改後,這篇草稿箱中的文字終於得以成型,撒花。nginx
六月更新架構的時候,去掉了 openresty
做爲服務器前端,取而代之的是裸跑 Traefik
,由於只暴露網關的 80
/ 443
,後面全部子容器都是以 expose
方案對內暴露端口到一塊虛擬網卡上,安全問題也不大,網關掛載着通配符證書,能夠方便的添加刪除後面的應用,雖然說用起來挺舒服的,可是有兩點始終讓我不是很爽。git
fail2ban
規則沒法使用了,也就是說得忍受大量掃描器污染日誌。問了一下以前出去創業的師傅,他們直接在給容器分配公網,壕無人道,並且直接分配公網 IP 配置項目也很多...github
如何能在最少配置的狀況下,最少資源消耗的狀況下,達到現有使用的便捷程度,便更爲了我這篇文字的主要目的。web
趕在休假結束以前,從新梳理了服務器運行環境和Traefik的使用,記錄下來,或許對摺騰「免」運維的服務的你也會有幫助。docker
在折騰具體配置以前,須要先提供標準的系統環境。編程
2018年第三個季度,Ubuntu 18.04 更新了快一個季度了,基本上該更新的軟件也都更新了,該兼容的軟件也都進行了兼容處理;Docker 在經歷更名風波後,版本迭代高歌猛進,一大波編排軟件蜂擁而至,如今版本也升級到了 v18 。json
考慮到後面軟件會作愈來愈多向後兼容的事情,16.04 的維護週期也近半,那麼此次就使用最新的系統和軟件來進行基礎環境的配置吧,這裏沒有選擇 CoreOS 是由於我這裏還有一些其餘軟件的使用需求,想在一個相對中立的環境中使用。
截止這篇文章寫成: 我使用的國外主流雲廠商皆支持 Ubuntu 18.04, 國內的雲廠商中,阿里雲支持,可是騰訊雲暫時還不支持。
若是你的雲主機廠商支持最新版本的系統,那麼能夠直接參考我下面給出的命令進行基礎環境配置。
若是你的雲主機廠商不支持,那麼請使用 do-release-upgrade
命令先進行手動升級,升級過程當中能夠一路 yes
,以及使用當前軟件維護的最新版本: install the package maintainer's version
。
下面開始介紹如何配置最基礎的系統環境。
先更新軟件包列表,升級軟件版本到最新的穩定版,而後爲避免系統中殘留一些老古董影響軟件運行,咱們要進行嘗試性的卸載老版本軟件操做,以及安裝一些經常使用軟件。
apt update && apt upgrade -y
apt remove docker docker-engine docker.io
apt install -y apt-transport-https ca-certificates curl software-properties-common
複製代碼
向系統中添加 Docker 官方 GPG Key,而後驗證該 Key 有效性,並更新倉庫源到系統,Ubuntu 18.04 會直接觸發拉取軟件包列表的操做,比較人性化,最後直接敲入 install
命令,進行社區版的 docker 安裝便可。
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
apt-key fingerprint 0EBFCD88
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
apt install -y docker-ce
複製代碼
在 https://github.com/docker/compose/releases
找到最新穩定版本安裝。
curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
複製代碼
至此,基礎的 docker 環境就安裝就緒了。
Docker version 18.06.1-ce, build e68fc7a
docker-compose version 1.22.0, build f46880fe
Storage Driver: overlay2
複製代碼
基礎的修改 ssh 端口,規避掃描器,應該人人都會,就略過不提,若是不會能夠百度或者翻閱以前的博客文章,咱們來講說 ufw 防火牆的配置。
服務默認會是未激活狀態,在激活以前,務必先豁免 ssh 端口,避免再使用 vnc 登陸上去補救。
> ufw status
Status: inactive
ufw all SSH_PORT
Rules updated
Rules updated (v6)
複製代碼
固然,若是你不喜歡修改 SSH 端口的話,能夠直接使用下面的命令。
ufw disable
ufw reset
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp
ufw allow 80/tcp
ufw enable
複製代碼
而後激活防火牆狀態。
ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup
複製代碼
防火牆啓動完畢,能夠順便折騰一下 fail2ban ,大幅減小常規的掃描器對於日誌的騷擾,和一些初級的猜解、滲透,後面再寫一篇詳述。
在配置完畢防火牆後,接下來能夠試驗配置是否生效,啓動一個映射到 80 端口的 nginx:alpine
鏡像,而後瀏覽器或者命令行訪問服務器公網IP,能夠看到熟悉的 nginx 默認歡迎頁,ufw 並無什麼做用。
root@VM-0-10-ubuntu:~# docker run --rm -p 80:80 nginx:alpine
Unable to find image 'nginx:alpine' locally
alpine: Pulling from library/nginx
911c6d0c7995: Pull complete
131e13eca73f: Pull complete
95376bf29516: Pull complete
6717402ec973: Pull complete
Digest: sha256:23e4dacbc60479fa7f23b3b8e18aad41bd8445706d0538b25ba1d575a6e2410b
Status: Downloaded newer image for nginx:alpine
114.xxx.xxx.xxx - - [27/Aug/2018:16:44:17 +0000] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36" "-"
2018/08/27 16:44:18 [error] 6#6: *1 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 114.xxx.xxx.xxx, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "119.28.182.48", referrer: "http://119.28.182.48/"
114.xxx.xxx.xxx - - [27/Aug/2018:16:44:18 +0000] "GET /favicon.ico HTTP/1.1" 404 571 "http://119.28.182.48/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36" "-"
複製代碼
這裏 ufw 沒有生效的緣由在於 docker 默認使用了 iptable 添加了一些轉發規則,壓根沒有走到 ufw 的規則中。
通常網上推薦的方案是,關閉這個特性,好比使用相似下面的操做。
echo '{"iptables": false}' | sudo tee /etc/docker/daemon.json > /dev/null
複製代碼
可是若是你真的這樣作了,接下來你將沒法得到客戶端訪問時,使用的IP信息,各個容器直接訪問互聯網、以及容器互通方面也會遇到一些小問題,而後你又不得不添加一些 iptable 去修正這個問題。
若是你仍是選擇關閉 iptable 特性,執行容器,那麼若是你想獲取客戶端IP,便只能使用如下幾個方案達成:
host
上,此時將再也不可以經過 docker ps
查看到你的容器端口狀態,只能經過 docker network inspect
網卡看到對應的端口開啓狀態,十分不利於維護。
docker run
命令,那麼須要配合 --net=host
參數。swarm
模式的 compose, 則須要聲明 network_mode: "host"
, compose 版本須要聲明 3.2 及以上, port
導出實際並不須要用繁瑣的模式定義。能夠看到,無論是哪一種方案,搞起來都十分繁瑣,並且不利於重複部署,將來調試維護成本過高了。
讓 Docker 保持默認配置和行爲,可是留出端口控制權給 UFW 以及外層的網關,子容器依舊所有使用 expose
使用私有化的方法導出端口給網關。
這個方案是否是看起來和上面小節中的方案1很類似,可是其實差異還不小,使用 Traefik 能夠在不不配 consul
/ zk
的狀況下,自動監聽 docker daemon
的情況,作到服務發現、負載均衡、可用性自動切換、甚至自動綁定域名證書。
以前不得不說是過度追求全容器方案,致使我使用 Traefik 都是在容器中。雖然說升級相對輕鬆,只須要修改 compose 配置中的版本字段便可,程序可用性也不須要太過關注,直接交付給 Linux Daemon 去維護,可是這樣就面臨一個問題,網關拿到數據的時候,已經通過了至少兩塊虛擬網卡的轉發,一來浪費性能,二來丟失客戶端IP,三來若是要保障更高級別的安全,還得關閉 docker iptable 轉發的特性,這個面臨的問題,上面的小節裏說的夠多了。
在決定「裸」運行 Traefik 後,咱們須要對它的配置進行必定的改動,我這裏提供一份最簡單的配置,相信已經能夠知足許多常見場景。
################################################################
# 全局設置
################################################################
# 激活調試模式 (默認關閉)
debug = true
# 日誌等級 (默認 ERROR)
logLevel = "INFO"
# 全局入口點類型 (默認 http)
defaultEntryPoints = ["https", "http"]
# 不上報統計信息
sendAnonymousUsage = false
################################################################
# 入口點設置
################################################################
[entryPoints]
# 默認前端
[entryPoints.http]
address = ":80"
compress = true
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
compress = true
[entryPoints.https.tls]
[[entryPoints.https.tls.certificates]]
certFile = "/data/ssl/your.com.cer"
keyFile = "/data/ssl/your.com.key"
# 控制檯端口
[entryPoints.traefik-api]
address = ":4399"
# Ping端口
[entryPoints.traefik-ping]
address = ":4398"
################################################################
# Traefik File configuration
################################################################
[file]
[backends]
[backends.dashboard]
[backends.dashboard.servers.server1]
url = "http://127.0.0.1:4399"
[backends.ping]
[backends.ping.servers.server1]
url = "http://127.0.0.1:4398"
[frontends]
[frontends.dashboard]
entrypoints = ["https"]
backend = "dashboard"
[frontends.dashboard.routes.route01]
rule = "Host:dashboard.your.com"
[frontends.ping]
entrypoints = ["https"]
backend = "ping"
[frontends.ping.routes.route01]
rule = "Host:ping.your.com"
[frontends.ping.routes.route02]
rule = "ReplacePathRegex: ^/ /ping"
################################################################
# Traefik logs configuration
################################################################
# Traefik logs
# Enabled by default and log to stdout
#
# Optional
#
# Default: os.Stdout
[traefikLog]
filePath = "/data/logs/traefik.log"
[accessLog]
filePath = "/data/logs/access.log"
# Format is either "json" or "common".
#
# Optional
# Default: "common"
#
# format = "common"
################################################################
# 訪問日誌 配置
################################################################
# Enable access logs
# By default it will write to stdout and produce logs in the textual
# Common Log Format (CLF), extended with additional fields.
#
# Optional
#
# [accessLog]
# Sets the file path for the access log. If not specified, stdout will be used.
# Intermediate directories are created if necessary.
#
# Optional
# Default: os.Stdout
#
# filePath = "/path/to/log/log.txt"
# Format is either "json" or "common".
#
# Optional
# Default: "common"
#
# format = "common"
################################################################
# API 及 控制檯 配置
################################################################
# 啓用API以及控制檯
[api]
# 入口點名稱
entryPoint = "traefik-api"
# 開啓控制檯(默認開啓)
dashboard = true
# 默認協議
defaultEntryPoints = ["https"]
################################################################
# Ping 配置
################################################################
# 啓用 ping
[ping]
# 入口點名稱
entryPoint = "traefik-ping"
################################################################
# Docker 後端配置
################################################################
# 啓用Docker後端
[docker]
# Docker服務後端
endpoint = "unix:///var/run/docker.sock"
# 默認域名
domain = "traefix.your.com"
# 監控docker變化
watch = true
# 使用自定義模板(可選)
# filename = "docker.tmpl"
# 對容器默認進行暴露(默認開啓)
# 若是關閉選項,則容器不包含 `traefik.enable=true` 標籤,就不會被暴露
exposedbydefault = false
# 使用綁定端口的IP地址取代內部私有網絡(默認關閉)
usebindportip = false
# 使用 Swarm Mode (默認關閉)
swarmmode = false
# Enable docker TLS connection.
#
# Optional
#
# [docker.tls]
# ca = "/etc/ssl/ca.crt"
# cert = "/etc/ssl/docker.crt"
# key = "/etc/ssl/docker.key"
# insecureskipverify = true
複製代碼
將配置作適當修改,保存以後,運行便可:
traefik -c /etc/traefik.toml
複製代碼
固然,此時你是沒法訪問到你的 Traefik 網關提供的服務的,爲何呢,由於這個軟件端口綁定會受限制於 UFW 的規則,因此咱們要更新 UFW 規則,容許外網訪問咱們的 80 和 443 端口。
root@VM-0-10-ubuntu:~# ufw allow 80
Rule added
Rule added (v6)
複製代碼
若是你操做順利,此刻你已經可以順利訪問你的網站了。
固然,這裏少了 docker daemon 的協助,進程管理仍是要看護一下的,推薦使用 supervisor 進行輔助管理,以前的博客有介紹過不止一次,有興趣能夠翻閱,這裏一樣給出一份最基礎的配置參考:
[program:traefik]
command=traefik -c /etc/traefik.toml --sendAnonymousUsage=false
user=root
autostart=true
startsecs=3
startretries=100
autorestart=true
stderr_logfile=/data/traefik/error.log
stderr_logfile_maxbytes=50MB
stderr_logfile_backups=10
stdout_logfile=/dara/traefik/access.log
stdout_logfile_maxbytes=50MB
stdout_logfile_backups=10
複製代碼
你的網關就就緒以後,咱們隨便找一個目錄使用一個叫作 whoami
的軟件鏡像幫助咱們驗證:網關可以如期的使用,除了自動服務發現,負載解析,還能提供包括統計、轉發、header重寫等功能。
version: '3'
services:
whoami:
image: emilevauge/whoami
expose:
- 80
labels:
- "traefik.enable=true"
- "traefik.port=80"
- "traefik.frontend.rule=Host:who.your.com"
複製代碼
將上面的配置保存爲 docker-compose.yml
,而後後臺運行起來。
瀏覽器或者命令行訪問 who.your.com
,得到下面的信息:
Hostname: b0cd60b18550
IP: 127.0.0.1
IP: 172.20.0.2
GET / HTTP/1.1
Host: who.your.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,ja;q=0.7
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
X-Forwarded-For: 221.xxx.xx.xxx
X-Forwarded-Host: who.your.com
X-Forwarded-Port: 443
X-Forwarded-Proto: https
X-Forwarded-Server: VM-0-10-ubuntu
X-Real-Ip: 221.xxx.xx.xxx
複製代碼
能夠看到服務發現、SSL證書掛載、源站IP轉發等功能都可以正確使用,並且不出意料,QPS 也會高很多(畢竟少了至少一層網絡轉發、至少一層完整的虛擬化)。
另外,因爲沒有修改 docker 的配置,容器不會出現不容許訪問外網的狀況,簡單驗證:
root@VM-0-10-ubuntu:/data/who# docker run -it --rm alpine ping -c 1 8.8.8.8
Unable to find image 'alpine:latest' locally
latest: Pulling from library/alpine
8e3ba11ec2a2: Pull complete
Digest: sha256:7043076348bf5040220df6ad703798fd8593a0918d06d3ce30c6c93be117e430
Status: Downloaded newer image for alpine:latest
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=46 time=14.075 ms
--- 8.8.8.8 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 14.075/14.075/14.075 ms
複製代碼
接下來就是逐步升級每臺服務器以及作數據遷移了。
其實關於容器內獲取外部IP,社區有大量討論,好比:#15086 等等,涉及不一樣的網卡模式,不一樣的編排工具,不一樣的端口映射模式,又有許多延伸話題。
而 Docker 和 UFW 防火牆的恩怨情仇,其實也是老化長談,可是不知道爲什麼,網上能看到的資料一邊倒到修改 iptable ...
但願本文可以給你一些額外的啓示,幫到正在使用 Traefik 和 Docker 來作服務化的你。
我如今有一個小小的折騰羣,裏面彙集了一些喜歡折騰的小夥伴。
在不發廣告的狀況下,咱們在裏面會一塊兒聊聊軟件、HomeLab、編程上的一些問題,也會在羣裏不按期的分享一些技術沙龍的資料。
喜歡折騰的小夥伴歡迎掃碼添加好友。(請註明來源和目的,不然不會經過審覈) 關於折騰羣入羣的那些事