Rails 線上持續整合部署(CI) 使用-Docker架構

docker-logoDocker

Docker

Docker的優點相信很多人都知道了, 並也開始導入Docker, 我們大約在半年前開始將所有的線上環境全部Docker化

早期在部署應用程式環境的時候, 並不是簡單的安裝一個程式或是相關套件等等, 才能完整的安裝一可以上線的正式環境 但是問題是並不是每次安裝都能夠順利, 例如:版本的相依問題, 等等等….

例外如果當初的應用程式是安裝在早期的作業系統上開發的 如果時過境遷, 作業系統已經升級, 相關套件也已經升級, 因為應用程式和當初開發時的一些套件都有相依性 這時要將當初的應用程式跑在當初的環境下, 會比安裝全新的更加不容易 但是如果當初將整個設定和應用程式的版號,作業系統等和相關套件做成一個Docker 這樣之後只需要執行這個Docker就可以重現當初的整個環境了 應用程式頁能正確運作了

所以發展出來的Ansibe和chef這種自動換安裝的伺服器相關套件的解決方案 但是這個個人覺得還有有一些局限性, 例如:作業系統平台不一樣 都還需要再做一些修正

Docker的出現解決了很多問題, 例如任何的作業系統只要有安裝Docker, 跑起來的結果是一樣的 代表不用再局限於安裝目標的作業系統和作業系統版本, 目前Mac,Linux和Windows都已經可以在上面運作Docker 了

他有別於以前作業系統的虛擬化,他是應用程式的虛擬化, 他在裡面包了一個很簡易的Linux的核心, 讓你感覺不出來的他和原生的應用程式跑在作業系統上有什麼差別, 因此在Docker裡面就可以將當初已經安裝的作業系統版本包含在裡面了, 例如:ubuntu14.04 LTS, 如果這個Docker 跑在CentOS上面, 其實他的整個運作就像是跑在ubuntu14.04 LTS上一樣, 因此才能做到完整的跨平台的運作

CI(Continuous integration, CI) 持續整合 CI是為了提高程式碼的品質,維持系統或是網站的穩定性, 他的核心理念就是, 當有新的程式碼被提交時, 就會自動進行一連串的自動化步驟:編譯,測試,和部署 等

如果是Compile語言的話, 就會先進行編譯看是否程式碼可以通過自動化編譯 再來就是最重要的自動化測試, 當一個新功能完成, 或是新的程式碼提交後, 很難保證 網站或是系統可以所以的功能都是在事先預料的情況下運作, 如果只是進行人工驗證, 通常會有預想不到且沒有驗證到的情況發生, 而造成網站出現沒事先預料的錯誤

因此做自動化測試將所有應該要驗證的功能都透過自動化去驗證一遍 自動化測試包含:測試每個class或是method的正確性的單元測試, 測試API是否正確運作, 整合測試等

線上Rails的Production環境, 且所有的服務都是運作在Docker上面, 該怎麼架設CI環境呢?

簡述如下: 有時間再補足

GitLab

Git版本控制是CI環境的核心

Jenkins

Jenkins && GitLab Plugins

GitLab有和Jenkins整合的Plugins 當有新的程式碼被commit時, 會自動Triger Jenkins執行自動化測試的動作

Capistrano && Docker

Capistrano是Rails的常用的自動化部屬工具

利用Capistrano自動將遠端的最新的Rails Code build一個最新的Docker

然後跑起來, 如果有自己架設 Docker registry 可以直接運行 速度會快很多

Jenkins && Capistrano 自動化部屬

利用Jenkins去呼叫Capistrano做自動化部屬

Run Auto Tesing in a clear Docker

在做自動化測試有一個很重要的要注意的地方, 就是要使用乾淨的環境進行測試 利用Jenkins Build一個乾淨且專門用於跑自動化測試的環境

[SEO]將網站改為https增加SEO和使用者的安全性

網站由於安全的意識抬頭 現在Google特別地將https提升搜尋引擎的排名 且如果是電子商務網站的站 建議還是要加上https

由於網站的整個傳輸過程都是加密的,所以會增加伺服器的加密和解密的效能負荷 但是我覺得進行這個投資還是值得

如果原先的網站是http的,但是原來的網站不想去做特別的更動設定 像說我原來的網站是用Docker架設的 但是不想去更動原來的Docker設定 要改成https的話 分享一個我覺得不錯的辦法

就是在網站前面架設一個Reverse Proxy 利用這個Reverse Proxy去做https的加密和解密

[Nginx]的ssl Reverse Proxy做法 可以參考這一篇文章 https://www.digitalocean.com/community/tutorials/how-to-configure-nginx-with-ssl-as-a-reverse-proxy-for-jenkins 這樣原先的網站就不用去做設定

如果原來的網站是用Wordpress架設的 要加上一個語法到wp-config.php

define('FORCE_SSL_ADMIN', true); // in some setups HTTP_X_FORWARDED_PROTO might contain // a comma-separated list e.g. http,https // so check for https existence if (strpos($\_SERVER['HTTP\_X_FORWARDED_PROTO'], 'https') !== false) $_SERVER['HTTPS']='on';

參考: https://codex.wordpress.org/Administration_Over_SSL

不然網站會一直進入無窮跳轉 原因是:

Reverse Proxy進來的流量轉成http進入第二層網站伺服器 但是網站伺服器的wordpress應用程式判斷目前並不是https的加密協定 因此進行跳轉到https, 然後https的流量進入Reverse Proxy之後 又轉成http進入了網站伺服器,所以繼續進行跳轉

所以上面那段語法是說明如果透過網路的http header的資料發現Reverse Proxy的那段是https的話 自動將的http轉成https,進行模擬網站伺服器的流量就是https

參考文章:

https://www.linode.com/docs/web-servers/nginx/nginx-ssl-and-tls-deployment-best-practices

線上持續整合部署(CI & CD) 使用Docker架構

CI(Continuous integration, CI) 持續整合,CI是為了提高程式碼的品質,維持系統或是網站的穩定性,他的核心理念就是,當有新的程式碼被提交時,就會自動進行一連串的自動化步驟:編譯,測試,和部署 等。

如果是Compile語言的話,就會先進行編譯看是否程式碼可以通過自動化編譯,再來就是最重要的自動化測試,當一個新功能完成,或是新的程式碼提交後,很難保證網站或是系統的功能都是在事先預料的情況下運作, 如果只是進行人工驗證, 通常會有預想不到且沒有驗證到的情況發生,而造成網站出現沒事先預料的錯誤。

因此做自動化測試將所有應該要驗證的功能都透過自動化去驗證一遍,自動化測試包含:測試每個class或是method的正確性的單元測試,測試API是否正確運作,整合測試等。

線上Rails的Production環境, 分享一下我們用Docker架設的CI環境。

1. Docker 環境

curl -sSL https://get.docker.com/ | sh

2. Docker Compose

docker compose 是Docker一個非常棒的工具,可以將docker如何運作整個寫在一個 docker-compose.yml 檔裡面。

根據設定檔啟動Docker

docker-compose up

停止Docker

docker-compose down

在ubuntu上安裝:

curl -L https://github.com/docker/compose/releases/download/1.14.0/docker-compose-`uname -s`-`uname -m`> /usr/local/bin/docker-compose` `sudo chmod +x /usr/local/bin/docker-compose

更詳細資料參考 https://docs.docker.com/compose/install/#where-to-go-next

3. GitLab Git版本控制是CI環境的核心

我們使用Gitlab來管理我們的源碼

https://github.com/sameersbn/docker-gitlab

4. Jenkins

我們用Jenkins來跑一些自動化測試的動作,完成後再在做自動化部屬

sudo docker run  -d  -p 8080:8080 \
--name jenkins  --restart=always -v /mnt/jenkins_home:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock jayqqaa12/jenkins`

ps: 這裡要注意的地方就是將運作Jenkins的Docker Contaniner裡的 docker.sock 掛載到Host的 docker.sock,這樣Jenkins的container雖然沒有安裝docker,但是也可以執行docker, 因為他直接呼叫Host的docker來執行,所以Jenkins編譯完成Docker Image會出現在Host上。

5. Jenkins && GitLab Plugins

GitLab有和Jenkins整合的Plugins,當有新的程式碼被commit時,會自動Triger Jenkins執行自動化測試的動作。

參考以下資料 https://docs.gitlab.com/ee/integration/jenkins.html

6. Jenkins 跑 自動化測試

我們的做法是gitlab當有新的個更新時,呼叫Jenkins去做一些工作。

Jenkins的工作會產生一個臨時的工作Docker,

在Docker裡面再跑一個Docker,

由這個Docker去執行自動化測試(Rspec等…),

沒問題後用個Docker跑自動化部屬。

#echo -e "[************************************************************ Run Test ************************************************************]"
docker run -e APPDIR='/app_path' -e RUN_SHELL_FILE='/app_path/test.sh' -e 
GIT_REPOSITORY_URL='ssh://app_path.git' registry.app.work:5000/docker_run_test:latest`

7.Capistrano && Docker

Capistrano是Rails的常用的自動化部屬工具,

如果自動化測試都沒問題後,由臨時的工作Docker呼叫Capistrano自動部署到線上的Server。

如果有自己架設 Docker registry 可以直接運行 速度會快很多。

Run Auto Tesing in a clear Docker

在做自動化測試有一個很重要的要注意的地方,就是要使用乾淨的環境進行測試。 所以上面的臨時的工作Docker,就是利用Jenkins Build一個乾淨且專門用於跑自動化測試和自動化測試的環境。

參考文章

  1. http://my.oschina.net/jayqqaa12/blog/633683
  2. http://www.ithome.com.tw/article/94710

TEAM工作流程

每個人:

  1. 每個人需要注意 自己被分配的任務
  2. 當開始進行自己的任務時, 記得將狀態更新為 “進行中”
  3. 如果任務開始處理後,當然無法完成, 記得填上 完成百分比, 如果可以填上進行任務時所花費的時數是最好
  4. 記得需要在完成日期前完成, 如果無法如期完成, 記得尋求大家協助

開發技術團隊:

  1. 每個人需要注意 自己被分配的任務
  2. 當開始進行自己的任務時, 記得將狀態更新為 “進行中”
  3. 如果任務開始處理後,當然無法完成, 記得填上 完成百分比, 如果可以填上進行任務時所花費的時數是最好
  4. 記得需要在完成日期前完成, 如果無法如期完成, 記得尋求大家協助
  5. 開始進行任務時, 從master開一個branch, 命名為 t+票號, 例如:222任務, 就開一個t222的branch在上面工作
  6. 完成後push到遠端的專案版本控制, 然後 發送pull request, 目前先指定我幫忙code review, 然後在code review的內容填上這個任務的工作內容, 和你覺得需要注意的地方
  7. 本機測試通過
  8. 自動化CI測試通過

後端工程師養成

  1. 學習Ruby的基本語法和觀念
  2. 學習Rails的相關語法和觀念 http://rubyonrails.org/ http://guides.rubyonrails.org/layouts_and_rendering.html https://ihower.tw/rails4/
  3. 學習Rails&Ruby自動化測試的相關基本知識 http://rspec.info/ https://github.com/zuazo/dockerspec http://betterspecs.org/
  4. Git團隊工作流程

WebServer Such As Nginx 效能調笑

1 KeepLive Connections

Clients generally open a number of simultaneous TCP connections to a server and conduct keepalive transactions across them all. These connections are held open until either the client or the server decides they are no longer needed, generally as a result of an idle timeout.

Modern web browsers typically open 6 to 8 keepalive connections and hold them open for several minutes before timing them out.

https://www.nginx.com/blog/http-keepalives-and-web-performance/

But:

The approach above is designed to give the best possible performance for an individual client. Unfortunately, in a ‘tragedy of the commons’-like scenario, if all clients operate in this way, it can have a detrimental effect on the performance of many common web servers and web applications

理論上的KeepLive Connections來增進連線效能的做法, 是只針對只有一個Server只有服務一個連線者的情況來說 但是實際上, 卻不會這麼理想, 往往會有很大量的使用者同時連線到伺服器請求資料, 因此如果每個使用者的KeepLive Connections的機制上運作, 而一旦當KeepLive Connections的數量達到了Server可以同時處理的concurrency上限時 就會出現嚴重得效能缺陷, 其他得使用者就無法再和此伺服器建立連線, 而出現拒絕服務的情況發生

The reason is that many servers have a fixed concurrency limit. For example, in common configurations, the Apache server can only process 150 (with the worker multi-processing module [MPM]) or 256 (with the prefork MPM) concurrent TCP connections. Each idle HTTP keepalive connection consumes one of these concurrency slots, and once all of the slots are occupied, the server cannot accept any more HTTP connections.

由於此機制造成可以提供一個拒絕服務攻擊(denial-of-service attacks)的一個情況發生

The large number of concurrent client connections and the assignment of a thread or process to each connection produces the phenomenon known as “HTTP Heavy Lifting” – a disproportionately large effort is required to process a lightweight HTTP transaction.

因為每一個同時連線的客戶端在運作上伺服器都會分配一個thread or process去對應處理使用者的請求,一個TCP的連線是很輕量的作業系統物件,但是執行緒和處理程序卻是很耗資源的,因此就會照成一個現象“HTTP Heavy Lifting”, 就是分配不成比例的資源去處理一個輕量的HTTP的交易

What Does This Mean in Practice?

It does not take many clients to exhaust the concurrency limit in many contemporary web and application servers.

If a client opens 8 TCP connections, and keeps them alive for 15 seconds after they are needed, the client consumes 8 concurrency slots for 15 seconds. If clients arrive at your website at the rate of 1 per second, 120 concurrency slots are continually occupied by idle keepalive connections. If the rate is 2 clients per second, 240 concurrency slots are occupied. Once the slots are exhausted, clients can no longer connect until the current connections time out.

This can result in very uneven levels of service. Clients who successfully acquire a keepalive connection can browse your service at will. Clients who are locked out have to wait in a queue.

在實作上代表什麼意思呢?

對很多現在化的網站和應用程式伺服器來說,當它一當達到並行服務的限制且無法排除時,就無法服務很多的客戶端

假如一個客戶端打開了8個TCP的連線, 在他不需要使用它時將它保持了15秒, 代表他使用了8個並行處理的通道15秒, 一當 達到了1個使用者端在1秒有120個並行通道被保持連線使用的使用率, 或者是2個使用者端在1秒有240個並行通道被保持連線使用的使用率時, 其他的使用者就無法再對伺服器進行連線, 直到他們的保持連線過期

如此會導致服務品質的不平均, 成功取得保持連線的客戶端可以使用網站的服務, 但是其他的使用者就必須在等待的序列當中而無法存取網站的服務

使用Docker 部屬 Production 解決 Zero Down Time

Docker的優點

早期在部署應用程式環境的時候, 並不是簡單的安裝一個程式或是相關套件等等, 才能完整的安裝一可以上線的正式環境 但是問題是並不是每次安裝都能夠順利, 例如:版本的相依問題, 等等等….

例外如果當初的應用程式是安裝在早期的作業系統上開發的 如果時過境遷, 作業系統已經升級, 相關套件也已經升級, 因為應用程式和當初開發時的一些套件都有相依性 這時要將當初的應用程式跑在當初的環境下, 會比安裝全新的更加不容易 但是如果當初將整個設定和應用程式的版號,作業系統等和相關套件做成一個Docker 這樣之後只需要執行這個Docker就可以重現當初的整個環境了 應用程式頁能正確運作了

所以發展出來的Ansibe和chef這種自動換安裝的伺服器相關套件的解決方案 但是這個個人覺得還有有一些局限性, 例如:作業系統平台不一樣 都還需要再做一些修正

Docker的出現解決了很多問題, 例如任何的作業系統只要有安裝Docker, 跑起來的結果是一樣的 代表不用再局限於安裝目標的作業系統和作業系統版本, 目前Mac,Linux和Windows都已經可以在上面運作Docker 了

他有別於以前作業系統的虛擬化,他是應用程式的虛擬化, 他在裡面包了一個很簡易的Linux的核心, 讓你感覺不出來的他和原生的應用程式跑在作業系統上有什麼差別, 因此在Docker裡面就可以將當初已經安裝的作業系統版本包含在裡面了, 例如:ubuntu14.04 LTS, 如果這個Docker 跑在CentOS上面, 其實他的整個運作就像是跑在ubuntu14.04 LTS上一樣, 因此才能做到完整的跨平台的運作

Docker部署時遇到的問題

What is Zero Time

High+Availability(高可靠性)

如何實作Zero Down Time

Docker Machine 快速開設雲端主機

Docker Machine

Docker Machine is a tool that lets you install Docker Engine on virtual hosts, and manage the hosts with docker-machine commands. You can use Machine to create Docker hosts on your local Mac or Windows box, on your company network, in your data center, or on cloud providers like AWS or Digital Ocean.

Install

$ curl -L https://github.com/docker/machine/releases/download/v0.7.0/docker-machine-uname -suname -m > /usr/local/bin/docker-machine && \ chmod +x /usr/local/bin/docker-machine

https://github.com/janeczku/docker-machine-vultr https://docs.docker.com/machine/get-started/ https://github.com/janeczku/docker-machine-vultr

實作iOS推播功能

1. 為何要有推播

Push Notification (推播) 是在APP上面很常見的功能 他可以主動的推播訊息到使用者的APP上面

在這裡主要以iOS的推播為主

說明一下為何需要有推播這個功能呢? 如果開發者需要傳送即時訊息到APP的話呢 其實APP也可以自己實作這個功能

方式就有很多種, 例如:最簡單的就是polling固定時間去APP的伺服器查看是否有新的資料 或是APP和伺服器建立一個socket連線通道, 伺服器可以主動的傳送推播資料到APP上

但是問題有兩點:

  1. iOS上面不提供APP在背景上執行這些功能
  2. 如果每個APP都自己實作這個功能的話, 會佔用大量的網路連線資源 和沒有統一的一套訊息傳送和顯示的方式

因次才會有APNS(Apple Push Notification service (APNs))來專門提供這個功能

2. Apple Push Notification service (APNs) 運作方式

3. 在Apple Developer Center 設定APP推播功能

4. iOS 取的Token

5. 取得的Token回傳到Server記錄下來

6. Server和APNS的溝通 如何產生pem

7. Ruby利用 https://github.com/rpush/rpush 來傳送推播資料到APNS

8. iOS Device 接收到推播訊息時, 使用者動作處理, 點選推播內容, 跳到指定內容