寫於 2018.02.19
前言
作為一個前端開發工程師,每天和瀏覽器、業務程式碼打交道,對於“前端”的概念算是比較熟悉了,主流的框架、工具等都能玩得轉,但總覺得自己一直都被禁錮在小小的所謂“前端”的圈子中——因為除此之外的知識點還是比較薄弱的。
後來在公司裡面獲得了一個輪崗的機會,進入到了運維團隊去學習,眼界也開闊了很多,對於自身水平的認識也更加深入,迫不及待想要提升自己“前端知識”以外的技能樹。
由於運維團隊經常會跟伺服器打交道,那麼我何不乾脆就從伺服器開始,好好折騰一遍呢?
一、購買伺服器
曾經考慮過購買騰訊雲或者阿里雲等國內伺服器,但是由於國內總所周知的原因,許多資源的下載要麼特別慢,要麼乾脆直接跪了,動不動就要切換源。同時如果域名繫結了國內的伺服器,都需要進行備案,實在是無比麻煩。毫無疑問,我最終選擇了國外的伺服器,世界瞬間就清淨了……
關於國外的伺服器選購,是見仁見智的事情,我選購的是一臺搬瓦工20G KVM伺服器,5美元/月,買了不吃虧買了不上當,然後安裝了Centos 7 x86_64 bbr系統,接下來就可以愉快地玩耍了。
二、購買域名
搭個什麼服務都好,總不能讓別人背自己的ip,如果能夠擁到一個拉風的域名還是很讚的。於是我就去萬網,直接以自己的英文名字jrainlau
申請了一個jrainlau.com
域名,一年才55塊RMB,真的超值哦~
很簡單的下單、支付,然後我就擁有了自己的專屬域名,接下來就是進行DNS解析了。
進入阿里雲的控制檯,找到雲解析DNS
,點進去就能看到我們的域名解析資訊了。新增兩條型別為A
的記錄,統統指向伺服器的ip地址即可:
三、安裝Nginx
在域名解析生效前的10分鐘裡面,足夠我們在伺服器上配置好Nginx了。
首先ssh登入伺服器:
ssh root@xxx.xxx.xxx.xxx -p yyyy
複製程式碼
輸入搬瓦工提供的登入密碼之後,順利登入。
但是如果每次登入伺服器都要輸入一遍那亂碼般的密碼,是很痛苦的一件事,所以果斷使用ssh-key來實現免密登入。
- 第一步,生成祕鑰(如果本機已存在可省略這一步)
按照提示選擇祕鑰所存放的目錄(ssh-keygen -t rsa 複製程式碼
~/.ssh/
),密碼留空,最後可以在設定的目錄裡找到生成的祕鑰:
- 第二步,上傳祕鑰到伺服器
然後按照提示輸入一遍密碼就可以了。以後想要登入伺服器就可以直接免密登入啦!ssh-copy-id root@xxx.xxx.xxx -p yyyy 複製程式碼
做完剛才的“分支任務”,回到我們配置Nginx的主線。
按照Nginx官網的文件,在CentOS中安裝Nginx是非常簡單的:
yum install -y nginx
複製程式碼
但是在實際操作中,卻發現一直提示No package nginx available
。搜了一圈,Stack Overflow裡面的回答都是因為可能沒有安裝epel
,於是馬上嘗試之:
yum install -y epel-release
複製程式碼
奇怪的是,執行結果提示epel已經存在,為nothing to do。然後當我嘗試安裝nginx的時候,發現還是no package nginx available。嘗試列出yum所有的源,發現根本沒有epel源:
yum repolist
源標識 源名稱 狀態
base/7/x86_64 CentOS-7 - Base 9,590+1
extras/7/x86_64 CentOS-7 - Extras 388
updates/7/x86_64 CentOS-7 - Updates 1,922+7
複製程式碼
後來經過一番折騰,才找到解決辦法:
# 首先進入/yum.repos.d目錄
cd /etc/yum.repos.d
# 然後編輯epel.repo檔案
vi epel.repo
[epel]
name=Extra Packages for Enterprise Linux 7 - $basearch
#baseurl=http://download.fedoraproject.org/pub/epel/7/$basearch
mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-7&arch=$basearch
failovermethod=priority
enabled=0
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
[epel-debuginfo]
name=Extra Packages for Enterprise Linux 7 - $basearch - Debug
#baseurl=http://download.fedoraproject.org/pub/epel/7/$basearch/debug
mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-debug-7&arch=$basearch
failovermethod=priority
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
gpgcheck=1
[epel-source]
name=Extra Packages for Enterprise Linux 7 - $basearch - Source
#baseurl=http://download.fedoraproject.org/pub/epel/7/SRPMS
mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-source-7&arch=$basearch
failovermethod=priority
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
gpgcheck=1
複製程式碼
可以看到,[epel]
和[epel-source]
裡面的enabled
都是0,解決辦法就在這裡,只要把0改成1,儲存退出後即可。
現在我們重新執行yum repolist
,會發現epel源已經被加上了:
源標識 源名稱 狀態
base/7/x86_64 CentOS-7 - Base 9,590+1
elrepo-kernel ELRepo.org Community Enterprise Linux Kernel Repository - el7 37
epel/x86_64 Extra Packages for Enterprise Linux 7 - x86_64 12,277
epel-source/x86_64 Extra Packages for Enterprise Linux 7 - x86_64 - Source 0
extras/7/x86_64 CentOS-7 - Extras 388
nodesource/x86_64 Node.js Packages for Enterprise Linux 7 - x86_64 22
updates/7/x86_64 CentOS-7 - Updates 1,922+7
repolist: 24,236
複製程式碼
再執行yum install -y nginx
,發現終於能夠成功安裝了!
nginx version: nginx/1.12.2
複製程式碼
接下來只要用一條指令即可開啟nginx:
nginx
複製程式碼
經過上面的一番折騰,域名的DNS解析早已生效了,此時輸入域名並回車,就能看到nginx的歡迎頁啦~
四、使用HTTPS
看到左上角“不安全”三個字,心裡是非常不爽的,於是馬上進行下一步工作,上HTTPS。
由於是個人伺服器,所以免費證書已經足夠了,另外為了方便起見,所以我使用了certbot
這個工具來幫我把伺服器升級成HTTPS。
首先通過yum下載安裝certbot
:
yum install certbot
複製程式碼
由於certbot伺服器在驗證域名的時候,會通過HTTP的方式訪問一個由certbot生成的靜態檔案,所以我們首先要在nginx裡面進行配置:
進入/etc/nginx
,然後編輯nginx.conf
,在server
裡面新增下列兩個location規則:
location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
root /usr/share/nginx/html;
}
location = /.well-known/acme-challenge/ {
return 404;
}
複製程式碼
可以看到,上面的root
我是指向了/usr/share/nginx/htm
,這個目錄是可以隨便指定的,我這麼寫完全是為了偷懶。
nginx配置好了以後,就可以使用certbot生成證書了:
# certbot certonly --webroot -w <root url> -d <hostname>
certbot certonly --webroot -w /usr/share/nginx/html/ -d xxxx.com
複製程式碼
如果看到下列的輸出,就證明證書已經生成成功了:
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/xxxx.com/fullchain.pem. Your cert
will expire on 20XX-09-23. To obtain a new or tweaked version of
this certificate in the future, simply run certbot again. To
non-interactively renew *all* of your certificates, run "certbot
renew"
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
複製程式碼
證書已經準備好了,我們還需要nginx的支援。重新開啟/etc/nginx/nginx.conf
,然後把註釋掉的https server給註釋回來:
server {
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
server_name xxxx.com;
root /home/www;
ssl_certificate "/etc/letsencrypt/live/xxxx.com/fullchain.pem";
ssl_certificate_key "/etc/letsencrypt/live/xxxx.com/privkey.pem";
ssl_trusted_certificate /etc/letsencrypt/live/xxxx.com/chain.pem;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
複製程式碼
ps: 上面的root我給配置了
/home/www
目錄,意味著以後只要是放在該目錄下的靜態資原始檔夾,我都可以通過https://xxx.com/資料夾名
直接進行訪問,更多關於nginx的配置請參考官方文件。
最後重啟一下nginx,就可以檢驗我們的頁面是否已經打上小綠標了:
nginx -s reload
複製程式碼
由於certbot所使用的letsencrypt證書只有90天的有效期,所以我們需要對它定期自動更新。
首先模擬更新:
sudo certbot renew --dry-run
# 看到如下輸出證明模擬更新成功
-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/your.domain.com.conf
-------------------------------------------------------------------------------
** DRY RUN: simulating 'certbot renew' close to cert expiry
** (The test certificates below have not been saved.)
Congratulations, all renewals succeeded. The following certs have been renewed:
/etc/letsencrypt/live/xxxx.com/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
** (The test certificates above have not been saved.)
複製程式碼
然後就可以使用crontab -e
命令來實現自動化了:
sudo crontab -e
#新增配置,每週一半夜3點00分執行renew:
00 3 * * 1 /usr/bin/certbot renew >> /var/log/le-renew.log
複製程式碼
五、部署靜態頁面與Node.js專案
伺服器已經準備了,HTTPS也弄好了,那麼接下來就可以部署我們的靜態頁面與nodejs專案了。
從前面的nginx配置可以知道,nginx對於域名為xxxx.com
的請求,都會請求到/home/www
目錄下,所以我們通過git或者scp等方式把靜態資源目放置在/home/www
目錄下即可。比方說我的markcook專案:
cd /home/www
git clone https://github.com/jrainlau/markcook -b gh-pages
複製程式碼
此時訪問 jrainlau.com/markcook 即可訪問到專案的頁面。
對於nodejs專案,我們使用pm2
來守護程式,讓專案在後臺執行。首先需要安裝nodejs,然後再安裝pm2:
curl -sL https://rpm.nodesource.com/setup_9.x | bash -
yum install nodejs
npm i pm2 -g
複製程式碼
接下來依然把nodejs專案通過git放置在/home/www
目錄下,進入目錄,執行下列命令:
npm i
pm2 start index.js --name my-server
┌─────────────┬────┬──────┬──────┬────────┬─────────┬────────┬─────┬───────────┬──────┬──────────┐
│ App name │ id │ mode │ pid │ status │ restart │ uptime │ cpu │ mem │ user │ watching │
├─────────────┼────┼──────┼──────┼────────┼─────────┼────────┼─────┼───────────┼──────┼──────────┤
│ my-server │ 0 │ fork │ 2306 │ online │ 22 │ 7h │ 0% │ 46.2 MB │ root │ disabled │
└─────────────┴────┴──────┴──────┴────────┴─────────┴────────┴─────┴───────────┴──────┴──────────┘
Use `pm2 show <id|name>` to get more details about an app
複製程式碼
最後在nginx.conf
裡面新增一條代理規則(假設node服務埠為3000):
location /my-server/ {
proxy_pass http://localhost:3000
}
複製程式碼
這樣,就能夠通過https://xxxx.com/my-server/
訪問到nodejs專案了。
六、使用travis-ci實現持續部署
剛才的操作僅僅是作為初次部署,如果以後程式碼有改動,還需要我們登入伺服器,進入到對應的專案目錄,手動執行git pull
,然後手動重啟伺服器(如果pm2啟動了watch模式可以省略這一步),相當麻煩。能不能有一種辦法,能夠在我提交程式碼的時候就自動更新伺服器的程式碼,並自動重啟伺服器呢?travis-ci
就是來實現這個目的的。
travis-ci支援公開專案和私有專案,是通過.org
和.com
字尾來區分的。以我的一個公開專案為例,首先進入https://travis-ci.org/ 官網,登入我的github賬號,然後會看到如下頁面:
找到需要整合travis-ci的專案,點選它前面的開關即可。
此時在travis-ci上的操作暫時告一段落,但是頁面先別關掉,先放在一邊。
接下來,我們回到本地開發機器,通過git clone
命令把這個專案克隆到本地,然後在專案根目錄下新增一個.travis.yml
檔案。這個檔案是travis-ci持續整合的關鍵,它定義了你所有持續整合的操作。為了簡單起見,我們僅僅使用它進行自動化部署:
language: node_js
node_js:
- 9.3.0
after_success:
- ssh root@xxx.xxx.xxx.xxx -p yyy 'cd /home/www/taxi-server && git pull && pm2 restart taxi-server'
複製程式碼
可以看到,我給她定義了執行環境為node.js 9.3.0
,在構建成功(其實啥也沒構建)之後,自動登入伺服器,拉取最新程式碼,重啟pm2。
大家都知道,登入伺服器是要輸入密碼的,即使是travis-ci幫我們自動化進行,這一步也免不了。但是由於輸入密碼的步驟是互動的,自動化處理不了,所以我們也要為travis-ci搞一套“免密登入”。經過上文ssh-key的配置,其實我們已經具備了這一條件,之不過還需要多幾步的操作。
-
在本地通過
gem
安裝travis
命令列工具(macOS預設支援ruby):gem install travis 複製程式碼
-
使用travis登入:
travis login 複製程式碼
然後輸入github的賬號密碼即可。
-
加密本地ssh-key並自動寫入
.travis.yml
:# --add參數列示自動新增指令碼到.travis.yml檔案中 travis encrypt-file ~/.ssh/id_rsa --add 複製程式碼
這時會看到.travis.yml
多了一段before_install
的內容:
before_install:
- openssl aes-256-cbc -K $encrypted_e65149523857_key -iv $encrypted_e65149523857_iv
-in id_rsa.enc -out ~\/.ssh/id_rsa -d
複製程式碼
然後把最後一行的“\
”轉義符刪掉,並換行頂格新增如下兩條內容:
- chmod 600 ~/.ssh/id_rsa
- echo -e "Host xxx.xxx.xxx.xxx\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
複製程式碼
切記把xxx.xxx.xxx.xxx
換成你伺服器的IP。
最後把新增.travis.yml
的專案push到github即可。
重新回到travis-ci.org的頁面,進入專案,就能夠看到持續整合的效果了:
這時候回到伺服器,執行pm2 logs
,會看到服務已經被自動重啟的日誌記錄,至此持續整合及部署功能完美成功!
尾聲
這一番折騰下來,總算把伺服器、建站、持續部署等知識囫圇摸了一遍,對這些技術棧也算有了一些粗淺的見解。接下來還有更多好玩的東西需要進行探索,畢竟這只是一個開始,大家一起共勉吧~