├── .gitignore ├── LICENSE ├── README.md ├── jenkins_host ├── api │ ├── Dockerfile │ └── requirements.txt └── docker-compose.yml ├── jenkins_nginx ├── README.md └── docker-compose.yml └── jenkins_volume ├── api ├── Dockerfile └── requirements.txt └── docker-compose.yml /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # SageMath parsed files 80 | *.sage.py 81 | 82 | # dotenv 83 | .env 84 | 85 | # virtualenv 86 | .venv 87 | venv/ 88 | ENV/ 89 | 90 | # Spyder project settings 91 | .spyderproject 92 | .spyproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | 97 | # mkdocs documentation 98 | /site 99 | 100 | # mypy 101 | .mypy_cache/ 102 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # docker-jenkins-django-tutorial 2 | 3 | 實戰 Docker + Jenkins + Django + Postgres 📝 4 | 5 | 這篇文章主要延續之前的教學文,建議對 Docker 以及 Django 有基礎的認識,可參考 6 | 7 | [Docker 基本教學 - 從無到有 Docker-Beginners-Guide](https://github.com/twtrubiks/docker-tutorial) 8 | 9 | [Django-REST-framework 基本教學 - 從無到有 DRF-Beginners-Guide 📝](https://github.com/twtrubiks/django-rest-framework-tutorial) 10 | 11 | * [目錄](https://github.com/twtrubiks/docker-jenkins-django-tutorial#ci--cd-%E4%BB%8B%E7%B4%B9) - [Youtube Tutorial PART 1 - CI ( Continuous Integration ) / CD (Continuous Delivery / Continuous Deployment) 介紹](https://youtu.be/wJlE0aFluY4) 12 | * [目錄](https://github.com/twtrubiks/docker-jenkins-django-tutorial#docker--jenkins--django--postgres-%E8%A8%AD%E5%AE%9A) - [Youtube Tutorial PART 2 - Docker + Jenkins + Django + Postgres 設定](https://youtu.be/fjwIVCywX2A) 13 | * [目錄](https://github.com/twtrubiks/docker-jenkins-django-tutorial#docker--jenkins--django--postgres-%E5%AF%A6%E6%88%B0%E6%95%99%E5%AD%B8) - [Youtube Tutorial PART 3 - Jenkins 基本設定](https://youtu.be/27rmiKGrG2M) 14 | * [目錄](https://github.com/twtrubiks/docker-jenkins-django-tutorial#jenkins--github-integration-plugin) - [Youtube Tutorial PART 4 - Jenkins + GitHub Integration 實戰](https://youtu.be/AYgw5NXAeNY) 15 | * [目錄](https://github.com/twtrubiks/docker-jenkins-django-tutorial#jenkins--github-webhooks-%E5%AF%A6%E6%88%B0) - [Youtube Tutorial PART 5 - Jenkins + GitHub Webhooks 實戰](https://youtu.be/ymfTEPxKRqQ) 16 | * [目錄](https://github.com/twtrubiks/docker-jenkins-django-tutorial#jenkins--bitbucket-private-repo-%E5%AF%A6%E6%88%B0) - [Youtube Tutorial PART 6 - Jenkins + BitBucket private repo 實戰](https://youtu.be/S6Hfcm_xrnE) 17 | * [目錄](https://github.com/twtrubiks/docker-jenkins-django-tutorial#jenkins--notifications---send-email) - [Youtube Tutorial PART 7 - Jenkins + Notifications - Send Email 實戰](https://youtu.be/MWWBleOtqVk) 18 | * [目錄](https://github.com/twtrubiks/docker-jenkins-django-tutorial#jenkins--slack) - [Youtube Tutorial PART 8 - Jenkins + Slack 實戰](https://youtu.be/jmVRb81KpUk) 19 | * [目錄](https://github.com/twtrubiks/docker-jenkins-django-tutorial#job-chaining-in-jenkins) - [Youtube Tutorial PART 9 - Jenkins Job chaining tutorial](https://youtu.be/FOhxViut4cI) 20 | * [目錄](https://github.com/twtrubiks/docker-jenkins-django-tutorial#delivery-pipeline-plugin) - [Youtube Tutorial PART 10 - Jenkins + Delivery Pipeline tutorial](https://youtu.be/kBAAtMOclv8) 21 | * [目錄](https://github.com/twtrubiks/docker-jenkins-django-tutorial#build-pipeline-plugin) - [Youtube Tutorial PART 11 - Jenkins + Build Pipeline tutorial](https://youtu.be/Dk4busLipS0) 22 | * [目錄](https://github.com/twtrubiks/docker-jenkins-django-tutorial#remote-access-api) - [Youtube Tutorial PART 12 - Jenkins + Remote access API tutorial](https://youtu.be/p7uxurX4MnI) 23 | 24 | * [目錄](https://github.com/twtrubiks/docker-jenkins-django-tutorial#csrf-protection) - CSRF Protection 25 | 26 | * [目錄](https://github.com/twtrubiks/docker-jenkins-django-tutorial#ssh-plugin---ssh-remote-hosts) - SSH Plugin - SSH remote hosts 27 | 28 | * [目錄](https://github.com/twtrubiks/docker-jenkins-django-tutorial#%E8%A8%AD%E5%AE%9A%E6%99%82%E5%8D%80) - 設定時區 29 | 30 | * [目錄](https://github.com/twtrubiks/docker-jenkins-django-tutorial#%E8%A8%AD%E5%AE%9A%E6%AC%8A%E9%99%90-security) - 設定權限 Security 31 | 32 | * [目錄](https://github.com/twtrubiks/docker-jenkins-django-tutorial/tree/master/jenkins_nginx) - jenkins 搭配 nginx 33 | 34 | ## CI / CD 介紹 35 | 36 | 在開始介紹前,先帶大家了解幾個名詞,相信大家一定常常聽到別人說 CI / CD, 37 | 38 | CI : Continuous Integration , 又稱 持續整合。 39 | 40 | CD : Continuous Delivery / Continuous Deployment , 又稱 持續交付 / 持續佈署。 41 | 42 | ![](https://i.imgur.com/s1hwUjr.jpg) 43 | 44 | 圖片來源 [http://www.code-maze.com/wp-content/uploads/2016/02/ci-4-1024x584.png](http://www.code-maze.com/wp-content/uploads/2016/02/ci-4-1024x584.png) 45 | 46 | 詳細的定義在這裡我就不另外做介紹,培養大家 google 的能力 :smiley: 47 | 48 | ### CI / CD 的好處 49 | 50 | CI 對團隊來講有非常多的好處,一個良好的 CI 能加速整個團隊的工作流程,而且 developer 不用擔心 51 | 52 | push 後整個專案可能會掛掉。也因為持續的佈署與測試,可以在早期就發現程式的漏洞( 盡早修正 bug 53 | 54 | ,越晚發現付出的代價越高 :scream: )。 55 | 56 | 透過 CI,可以為團隊帶來更好的溝通,也可以更容易的進行 Code Review ,提升整個工作團隊的效率, 57 | 58 | 減少不必要的手動流程 ( 自動化 ),developer 可以更專注的在開發程式。 59 | 60 | CI 不只對 developer 有好處,也對管理者有好處,可以隨時監控目前整個團隊的工作流程以及品質。 61 | 62 | ### 該選擇哪一款 CI / CD 呢 63 | 64 | 因為這類工具很多,在這裡我挑幾個 65 | 66 | [Jenkins](https://jenkins-ci.org/) 67 | 68 | ![](https://i.imgur.com/lQefqzU.jpg) 69 | 70 | [GitLab CI](https://docs.gitlab.com/) 71 | 72 | ![](https://i.imgur.com/ThRu34A.jpg) 73 | 74 | [Travis CI](https://travis-ci.org/) 75 | 76 | ![](https://i.imgur.com/vWiOoH4.jpg) 77 | 78 | [Drone](https://github.com/drone/drone) 79 | 80 | ![](https://i.imgur.com/o34VAYY.jpg) 81 | 82 | 該選擇哪一個呢 ? 83 | 84 | 基本上,還是要依照自己的的需求、技術、工作流程來選擇最適合你們團隊的。 85 | 86 | 但這篇文章的主角是 Jenkins :smile: 87 | 88 | ## Docker + Jenkins + Django + Postgres 設定 89 | 90 | 使用 [Docker 基本教學 - 從無到有 Docker-Beginners-Guide](https://github.com/twtrubiks/docker-tutorial) 當作範例, 91 | 92 | 主要是 docker-compose.yml 裡面的設定,有兩種設定方式, 93 | 94 | 一種是將路徑同步到你的 host 本機,另一種是 Named volume。 95 | 96 | 可參考官網 volumes 設定方式 [docker-short-syntax](https://docs.docker.com/compose/compose-file/#short-syntax-3) 97 | 98 | 方法一: 同步到你的 host 本機 99 | 100 | 可參考 [jenkins_host](https://github.com/twtrubiks/docker-jenkins-django-tutorial/tree/master/jenkins_host) 101 | 102 | [docker-compose.yml](https://github.com/twtrubiks/docker-jenkins-django-tutorial/blob/master/jenkins_host/docker-compose.yml) 103 | 104 | ```yml 105 | version: '3' 106 | services: 107 | 108 | db: 109 | image: postgres 110 | environment: 111 | POSTGRES_PASSWORD: password123 112 | ports: 113 | - "5432:5432" 114 | volumes: 115 | - pgdata_jenkins_host:/var/lib/postgresql/data/ 116 | 117 | api: 118 | build: ./api 119 | restart: always 120 | command: python manage.py runserver 0.0.0.0:8000 121 | ports: 122 | - "8002:8000" 123 | volumes: 124 | - ./workspace/workspace/demo/api:/docker_api 125 | depends_on: 126 | - db 127 | 128 | jenkins: 129 | image: jenkins/jenkins:lts-jdk11 130 | restart: always 131 | ports: 132 | - "8080:8080" 133 | - "50000:50000" 134 | volumes: 135 | - ./workspace:/var/jenkins_home 136 | volumes: 137 | pgdata_jenkins_host: 138 | ``` 139 | 140 | 方法二: Named volume 141 | 142 | 可參考 [jenkins_volume](https://github.com/twtrubiks/docker-jenkins-django-tutorial/tree/master/jenkins_volume) 143 | 144 | [docker-compose.yml](https://github.com/twtrubiks/docker-jenkins-django-tutorial/blob/master/jenkins_volume/docker-compose.yml) 145 | 146 | ```yml 147 | version: '3' 148 | services: 149 | 150 | db: 151 | image: postgres 152 | environment: 153 | POSTGRES_PASSWORD: password123 154 | ports: 155 | - "5432:5432" 156 | volumes: 157 | - pgdata_jenkins:/var/lib/postgresql/data/ 158 | 159 | api: 160 | build: ./api 161 | restart: always 162 | command: python /var/jenkins_home/workspace/demo/api/manage.py runserver 0.0.0.0:8000 163 | ports: 164 | - "8002:8000" 165 | volumes: 166 | - api_data:/docker_api 167 | - jenkins_data:/var/jenkins_home 168 | depends_on: 169 | - db 170 | 171 | jenkins: 172 | image: jenkins/jenkins:lts-jdk11 173 | restart: always 174 | ports: 175 | - "8080:8080" 176 | - "50000:50000" 177 | volumes: 178 | - jenkins_data:/var/jenkins_home 179 | volumes: 180 | api_data: 181 | jenkins_data: 182 | pgdata_jenkins: 183 | ``` 184 | 185 | ## Docker + Jenkins + Django + Postgres 實戰教學 186 | 187 | 一樣一行指令啟動:relaxed: 188 | 189 | > docker-compose up 190 | 191 | 直接瀏覽 [http://localhost:8080/](http://localhost:8080/),會看到下圖 192 | 193 | ![](https://i.imgur.com/nMXQc7Z.jpg) 194 | 195 | 進入 jenkins container 196 | 197 | > cat /var/jenkins_home/secrets/initialAdminPassword 198 | 199 | ![](https://i.imgur.com/6LNxk8F.png) 200 | 201 | 將得到的 password 貼到 Administrator password 即可, 202 | 203 | 再來是安裝套件,請依照自己的需求選擇套件,也可以都不要裝, 204 | 205 | 需要的時候再補裝套件:smirk: 206 | 207 | ![](https://i.imgur.com/34d8NHY.jpg) 208 | 209 | 依照你選擇的套件決定安裝速度 210 | 211 | ![](https://i.imgur.com/j5W5uKh.jpg) 212 | 213 | 設定你的帳號密碼 214 | 215 | ![](https://i.imgur.com/cnV0DYb.jpg) 216 | 217 | 接著我們就可以開始了 218 | 219 | ![](https://i.imgur.com/03Lzw5i.jpg) 220 | 221 | ### Jenkins + GitHub Integration Plugin 222 | 223 | 整合 Jenkins + GitHub :satisfied: 224 | 225 | 先點選左側的 管理 Jenkins 226 | 227 | ![](https://i.imgur.com/G110omM.jpg) 228 | 229 | 選擇 管理外掛程式 230 | 231 | ![](https://i.imgur.com/qkPBoJx.jpg) 232 | 233 | 接著搜尋 GitHub Integration Plugin,如果你已經安裝則會出現在已安裝那邊 234 | 235 | ![](https://i.imgur.com/j2pgRDP.png) 236 | 237 | 安裝完成後,點選左側的新增作業 238 | 239 | ![](https://i.imgur.com/Vaksz9s.jpg) 240 | 241 | 建立一個專案稱為 demo 242 | 243 | ![](https://i.imgur.com/xb6mFoA.jpg) 244 | 245 | 描述可以輸入對這專案的說明 246 | 247 | ![](https://i.imgur.com/MKRrIti.jpg) 248 | 249 | 選擇 Git , 這邊使用 **public** 的 REPO, 250 | 251 | [Docker 基本教學 - 從無到有 Docker-Beginners-Guide 教你用 Docker 建立 Django + PostgreSQL](https://github.com/twtrubiks/docker-tutorial) 252 | 253 | ( 後面會說明如何使用 **private** 的 REPO ) 254 | 255 | ![](https://i.imgur.com/qqXx7j9.jpg) 256 | 257 | 設定完畢之後,選擇馬上建置,你會發現他開始 build 了 :grin: 258 | 259 | ![](https://i.imgur.com/xewlYwA.jpg) 260 | 261 | 接著你可以到工作區看,你會發現已經把剛剛的專案順利 clone 下來了:+1: 262 | 263 | ![](https://i.imgur.com/ARSYVvm.jpg) 264 | 265 | 接著建議將 api 重新啟動,然後進入 api container 執行必要的指令 266 | 267 | ```cmd 268 | python manage.py makemigrations musics 269 | python manage.py migrate 270 | python manage.py createsuperuser 271 | ``` 272 | 273 | ![](https://i.imgur.com/ph7o3pU.png) 274 | 275 | ![](https://i.imgur.com/jZXjdjC.png) 276 | 277 | 執行完畢之後,我們就可以到 [http://localhost:8002/api/music/](http://localhost:8002/api/music/) 瀏覽。 278 | 279 | ![](https://i.imgur.com/lzsHjlL.png) 280 | 281 | 也可以設定遠端觸發建置 282 | 283 | ![](https://i.imgur.com/Krn70Vi.png) 284 | 285 | 也就是設定一組 token,例如 twtrubiks, 286 | 287 | 當我輸入網址 [http://localhost:8080/job/demo/build?token=twtrubiks](http://localhost:8080/job/demo/build?token=twtrubiks) 就會自動開始 build 。 288 | 289 | ### Jenkins + GitHub Webhooks 實戰 290 | 291 | 聰明的你現在一定會問,這樣我每次 push 完,都要自己再去 jenkins build ,有夠麻煩 :expressionless: 292 | 293 | 能不能 push 之後,透過 Webhooks 讓 jenkins 偵測到,然後自動 build 呢 :question: 294 | 295 | 當然可以 :flushed: 296 | 297 | 由於需要 https , 所以我們透過 ngrok 幫助我們完成,可參考 [如何使用 ngrok](https://github.com/twtrubiks/facebook-messenger-bot-tutorial#%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8-ngrok) 298 | 299 | > ./ngrok http 8080 300 | 301 | port 設定 8080 是因為 jenkins 的 port 為 8080 302 | 303 | ![](https://i.imgur.com/MYv5Z59.png) 304 | 305 | 點選組態 306 | 307 | ![](https://i.imgur.com/vbQrNkF.png) 308 | 309 | 找到建置觸發程序,並選擇 GitHub hook trigger for GITScm polling 310 | 311 | ![](https://i.imgur.com/NXtvmVZ.png) 312 | 313 | 接著到 [Docker 基本教學 - 從無到有 Docker-Beginners-Guide 教你用 Docker 建立 Django + PostgreSQL](https://github.com/twtrubiks/docker-tutorial) 314 | 315 | 專案中設定 Webhooks ( 你可以直接 fork 這個專案去改 ) 316 | 317 | ![](https://i.imgur.com/xwtkmOO.png) 318 | 319 | Payload URL 就是填入 ngrok 幫你產生的 https 的網址,記得要在網址後面補上 `github-webhook`, 320 | 321 | 例如範例的 [https://65daeaf5.ngrok.io/github-webhook/](https://65daeaf5.ngrok.io/github-webhook/ ) 322 | 323 | ![](https://i.imgur.com/zGLgLlh.png) 324 | 325 | 如果設定正確,會有一個綠色的小勾勾 326 | 327 | ![](https://i.imgur.com/sbZwq9n.png) 328 | 329 | 這時候,你可以對  [Docker 基本教學 - 從無到有 Docker-Beginners-Guide 教你用 Docker 建立 Django + PostgreSQL](https://github.com/twtrubiks/docker-tutorial) 330 | 331 | 專案 commit 後再 push,你會發現 jenkins 自動開始 build 了 :satisfied: 332 | 333 | ![](https://i.imgur.com/kkLJ6nr.png) 334 | 335 | 也可以點選左側的 GitHub Hook Log 觀看紀錄 336 | 337 | ![](https://i.imgur.com/wJilA17.png) 338 | 339 | ### Jenkins + BitBucket private repo 實戰 340 | 341 | 如果你是使用 **private** 的 REPO, 需要多設定 SSH KEY ,這裡使用 BitBucket 當作範例。 342 | 343 | 首先,進入你的 jenkins container 產生 ssh key ,可參考 [generating-a-new-ssh-key](https://help.github.com/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent/#generating-a-new-ssh-key)。 344 | 345 | 如果還是不懂,也可參考 [Git-Tutorials GIT 基本使用教學](https://github.com/twtrubiks/Git-Tutorials),或是直接看之前的影片教學 346 | 347 | [github 基本教學 - 從無到有](https://www.youtube.com/watch?v=py3n6gF5Y00),影片教學包含如何產生 SSH key。 348 | 349 | ![](https://i.imgur.com/THw32js.png) 350 | 351 | > cat /var/jenkins_home/.ssh/id_rsa.pub 352 | 353 | ![](https://i.imgur.com/vbgfzhJ.png) 354 | 355 | 到你的 BitBucket private repo 的地方設定 356 | 357 | ![](https://i.imgur.com/eWC0GWz.png) 358 | 359 | 貼上剛剛的 id_rsa.pub 360 | 361 | ![](https://i.imgur.com/khM9X0n.png) 362 | 363 | 如果你貼上一個 private repository,你會發現會有紅色警告 364 | 365 | ![](https://i.imgur.com/RpfbFJu.png) 366 | 367 | 這時候有兩種方法 Add Credentials 368 | 369 | 第一種 370 | 371 | ![](https://i.imgur.com/h3DE2b7.png) 372 | 373 | 第二種 ( 安全一點 :stuck_out_tongue: ) 374 | 375 | ![](https://i.imgur.com/5J5ZpGW.png) 376 | 377 | 如果設定正確,你會發現紅字消失了 378 | 379 | ![](https://i.imgur.com/bOF7ZsK.png) 380 | 381 | ### Jenkins + Notifications - Send Email 382 | 383 | 管理 Jenkins -> 設定系統 384 | 385 | ![](https://i.imgur.com/lZwWdXS.png) 386 | 387 | 找到電子郵件通知,並且設定,這邊使用 gmail 當作範例, 388 | 389 | 測設定完成後你也可以寄測試信看看設定有沒有正確 :relaxed: 390 | 391 | ![](https://i.imgur.com/4vOsthJ.png) 392 | 393 | 如果你使用 gmail,然後一直寄不出去,你可以參考 [使用-gmail-寄信---前置作業](https://github.com/twtrubiks/Flask-Mail-example#使用-gmail-寄信---前置作業) 的設定。 394 | 395 | 接著再回到專案的組態 396 | 397 | ![](https://i.imgur.com/vbQrNkF.png) 398 | 399 | 選擇電子郵件通知 400 | 401 | ![](https://i.imgur.com/gmYMohn.png) 402 | 403 | 輸入建立失敗時,誰要收到 email 通知 404 | 405 | ![](https://i.imgur.com/EDGB577.png) 406 | 407 | ### Jenkins + Slack 408 | 409 | 這裡使用 [Slack](https://slack.com/) 當作範例 :blush: 410 | 411 | 之前我也有簡單整合過 [Slack](https://slack.com/), 412 | 413 | 可參考[使用Hubot建立屬於自己的機器人 (Build Your Own Robot With Hubot)](https://github.com/twtrubiks/mybot)。 414 | 415 | 安裝 Slack Notification Plugin 416 | 417 | ![](https://i.imgur.com/T3apVow.png) 418 | 419 | 接著到你自己的 [Slack](https://slack.com/) ( 申請步驟這邊不介紹了 ),點選左邊 Channels 的 + 420 | 421 | ![](https://i.imgur.com/PibIvkJ.png) 422 | 423 | 建立一個 channel 424 | 425 | ![](https://i.imgur.com/8vEnSx8.png) 426 | 427 | 點選右上角齒輪 Add an app 428 | 429 | ![](https://i.imgur.com/ceEYhCg.png) 430 | 431 | 搜尋 jenkins 432 | 433 | ![](https://i.imgur.com/VrsiDJi.png) 434 | 435 | Install 436 | 437 | ![](https://i.imgur.com/zE5MXpQ.png) 438 | 439 | 接著會有圖文教學教你如何將 Slack 整合進去 jenkins 440 | 441 | ![](https://i.imgur.com/zayZzKU.png) 442 | 443 | 要設定的有三個地方,分別為 **Base URL**、**Integration Token**、**Chnnel** 444 | 445 | ![](https://i.imgur.com/uQmedh6.png) 446 | 447 | 你的 Post to Channel 448 | 449 | ![](https://i.imgur.com/aHkZw0C.png) 450 | 451 | 回到 Jenkins,左側管理 Jenkins,設定系統 452 | 453 | ![](https://i.imgur.com/LGp8yn0.png) 454 | 455 | 找到 Slack, 設定 *Workspace* *Credential* *Default channel / member id* 456 | 457 | ![](https://i.imgur.com/jUmj4c3.png) 458 | 459 | 點選 Add Credential ( 使用這個安全一點:relaxed: ) 460 | 461 | ![](https://i.imgur.com/f3q4kzC.png) 462 | 463 | 最後可以點 Test Connection 測試看看是否設定正確,如果正確會顯示 Success :grin: 464 | 465 | 接著再回到 jenkins 專案裡的組態 466 | 467 | ![](https://i.imgur.com/8MMxUEa.png) 468 | 469 | 點選 建置後動作 並選擇 Slack Notifications 470 | 471 | ![](https://i.imgur.com/djodDCN.png) 472 | 473 | 依照自己需求通知的做設定 474 | 475 | ![](https://i.imgur.com/vPy8eyR.png) 476 | 477 | 接著設定完成,讓我們來試試看 :flushed: 478 | 479 | 可以手動點選馬上建置或是如果你已經 GitHub Integration Plugin 直接 commit push 一次即可, 480 | 481 | 回到你的 slack 你會發現成功了 :satisfied: 482 | 483 | ![](https://i.imgur.com/qLLEDsa.png) 484 | 485 | ## 軟體版本週期 486 | 487 | 既然都對 CI / CD 有基本的認識了,那麼你一定要再了解軟體版本週期。這個是什麼呢?我相信 488 | 489 | 大家一定常常聽導什麼 Alpha Beta 之類的,其實這就是指軟體版本的週期,以下我將簡單介紹他 490 | 491 | 的週期。 492 | 493 | ### Alpha 494 | 495 | Alpha( α )版本基本上就是測試版本,很多功能都未完善,因為是屬於軟體版本週期中的最初階 496 | 497 | 段。這階段通常會由開發者下去做測試。 498 | 499 | ### Beta 500 | 501 | Beta 版本是最早對外公開的軟體版本,由一般大眾協助測試,通常 Beta 版本包含所有的功能,但 502 | 503 | 可能會有一些已知的 bug,Beta 版本有時候也會作為測試市場對產品的反應。 504 | 505 | ### Release Candidate 506 | 507 | Release Candidate( 簡稱 RC ),通常這版本會成為最終產品候選的版本,這階段通常不會有嚴重 508 | 509 | 的 bug,有些開源軟體會推出 RC2,而 RC2 則會成為正式版本。 510 | 511 | ### Release to Manufacting 512 | 513 | Release to Manufacting( 簡稱 RTM ),這版本基本上是已經要上線了。 514 | 515 | ### General availability 516 | 517 | General availability( 簡稱 GA ),這階段軟體基本上已機上線了。 518 | 519 | ## Job chaining in Jenkins 520 | 521 | 依照文章最開始的 CI / CD 介紹的圖,使用簡單 Build -> Deploy -> Test 的 workflow, 522 | 523 | 依照這個 workflow,我將介紹 Jenkins 的 Job chaining 524 | 525 | * [Youtube Tutorial PART 9 - Jenkins Job chaining tutorial](https://youtu.be/FOhxViut4cI) 526 | 527 | ## Build / Delivery Pipeline Plugin 528 | 529 | 剛剛介紹了 Job chaining 的概念,接下來要推薦大家可以將 Job chaining 視覺化的套件。 530 | 531 | ### Delivery Pipeline Plugin 532 | 533 | * [Youtube Tutorial PART 10 - Jenkins + Delivery Pipeline tutorial](https://youtu.be/kBAAtMOclv8) 534 | 535 | [Delivery Pipeline Plugin](https://wiki.jenkins.io/display/JENKINS/Delivery+Pipeline+Plugin) 536 | 537 | Delivery Pipeline Plugin 要求 job 要有 downstream/upstream relationships (上下游的關係)。 538 | 539 | ### Build Pipeline Plugin 540 | 541 | * [Youtube Tutorial PART 11 - Jenkins + Build Pipeline tutorial](https://youtu.be/Dk4busLipS0) 542 | 543 | [Build Pipeline Plugin](https://wiki.jenkins.io/display/JENKINS/Build+Pipeline+Plugin) 544 | 545 | ## Remote access API 546 | 547 | 建議看影片,實戰給大家看會比較有感覺 😁 548 | 549 | * [Youtube Tutorial PART 12 - Jenkins + Remote access API tutorial](https://youtu.be/p7uxurX4MnI) 550 | 551 | 可參考 [Remote access API](https://wiki.jenkins.io/display/JENKINS/Remote+access+API)。 552 | 553 | 主要是我們可以透過 terminal 呼叫 API,達到幫我們 build 的功能。 554 | 555 | 如何取得自己的 User ID 以及 API Token ,請先點選右上角 556 | 557 | ![](https://i.imgur.com/vEHGxH6.png) 558 | 559 | 設定 -> API Token 560 | 561 | ![](https://i.imgur.com/ZgfPxpK.png) 562 | 563 | 點選顯示 API Token 後, 564 | 565 | ![](https://i.imgur.com/35Z4rao.png) 566 | 567 | 溫馨小提醒 :heart: 568 | 569 | 以下使用 curl 來當做範例,如果你是 windows 或 Linux 用戶, 570 | 571 | 請自己安裝 curl,這邊就不再做介紹了☺️ 572 | 573 | 官方範例 574 | 575 | ```cmd 576 | curl -X POST JENKINS_URL/job/JOB_NAME/build \ 577 | --user USER:TOKEN \ 578 | --data-urlencode json='{"parameter": [{"name":"id", "value":"123"}, {"name":"verbosity", "value":"high"}]}' 579 | ``` 580 | 581 | 範例,假設 job 為 demo 582 | 583 | ```cmd 584 | curl -X POST http://localhost:8080/job/demo \ 585 | --user twtrubiks:8d3215553ca9623300f4967827c61291 586 | ``` 587 | 588 | `-d` 參數說明 589 | 590 | > -d/--data , Send specified data in POST request. 591 | 592 | `--data-urlencode` 參數說明 593 | 594 | > --data-urlencode , (HTTP) This posts data, similar to the other -d, --data options with the exception that this performs URL-encoding. 595 | 596 | `-u` 參數說明 597 | 598 | > -u/--user , Set user and password 599 | 600 | 範例 601 | 602 | ```cmd 603 | curl --user name:password http://www.example.com 604 | curl -u user:password http://www.example.com 605 | ``` 606 | 607 | `-X` 參數說明 608 | 609 | > -X/--request The request method to use. 610 | 611 | 範例 612 | 613 | ```cmd 614 | curl -X POST http://www.example.com 615 | ``` 616 | 617 | 如果在 terminal 中輸入後,什麼都沒發生,就代表成功了( 但通常應該都會有錯誤😅 ), 618 | 619 | 如果,你看到以下錯誤 620 | 621 | ```cmd 622 | .... 623 | Error 403 No valid crumb was included in the request 624 | .... 625 | ``` 626 | 627 | ![](https://i.imgur.com/QYhNler.png) 628 | 629 | 就代表你有啟動比較安全的機制 CSRF Protection( 預設是啟動的 )。 630 | 631 | 要如何解決呢? 請繼續往下看😊 632 | 633 | ### CSRF Protection 634 | 635 | 主要是防止 CSRF 攻擊, 636 | 637 | 如果不知道什麼是 CSRF ,可參考我之前寫的 [CSRF-tutorial 📝](https://github.com/twtrubiks/CSRF-tutorial) 638 | 639 | 管理 Jenkins -> 設定全域安全性 640 | 641 | ![](https://i.imgur.com/78mW8qh.png) 642 | 643 | 防範 CSRF 入侵預設有被打勾 644 | 645 | ![](https://i.imgur.com/auFI5Uy.png) 646 | 647 | 把打勾取消,就可以用剛剛的方法了。 648 | 649 | 但是,如果我還是希望打勾防範 CSRF 入侵,那我該怎麼辦呢😬 650 | 651 | 這時候,必須先得到 Jenkins-Crumb 652 | 653 | ```cmd 654 | curl -s -u twtrubiks:8d3215553ca9623300f4967827c61291 http://localhost:8080/crumbIssuer/api/json 655 | ``` 656 | 657 | ![](https://i.imgur.com/WgrbIKi.png) 658 | 659 | `-s` 參數說明 660 | 661 | > -s/--silent Silent mode. Don't output anything 662 | 663 | 然後再將 Jenkins-Crumb 的值帶進去,如下( 假設 job 為 demo ) 664 | 665 | ```cmd 666 | curl -X POST http://localhost:8080/job/demo/build --user twtrubiks:8d3215553ca9623300f4967827c61291 -H "Jenkins-Crumb:6fbe69cd42a261330cb37e74af1ed1d1" 667 | ``` 668 | 669 | ![](https://i.imgur.com/xwmGGO2.png) 670 | 671 | `-H` 參數說明 672 | 673 | > -H/--header Custom header 674 | 675 | 如果沒跳出任何資訊 ( 有跳訊息通常是有錯誤 ),就代表成功了👍 676 | 677 | ![](https://i.imgur.com/lqb8HQL.png) 678 | 679 | 你可以回到你的 Jenkins ,你會發現他自動開始 build 了 :satisfied: 680 | 681 | ### SSH Plugin - SSH remote hosts 682 | 683 | 這個 Jenkins Plugin 可以幫助你遠端 ssh 到主機上執行 script, 684 | 685 | 請到 Manage Jenkins -> Manage Plugins 底下安裝 Plugin 686 | 687 | ![alt tag](https://i.imgur.com/EDE9SB8.png) 688 | 689 | 之後到 Manage Jenkins -> System Configuration -> Configure System 底下 690 | 691 | 設定你的 SSH remote hosts 692 | 693 | ![alt tag](https://i.imgur.com/sBWXYfB.png) 694 | 695 | 最後你到一般的 job 裡就會看到 Execute shell script on remote host using ssh 696 | 697 | ![alt tag](https://i.imgur.com/dI9PD44.png) 698 | 699 | 順便補充一下, aws ssh key 設定的部份, 700 | 701 | Kind 的部份選擇 SSH Username with private key 702 | 703 | ![alt tag](https://i.imgur.com/79D9SbG.png) 704 | 705 | 這邊再把你的 key 貼上去 706 | 707 | ![alt tag](https://i.imgur.com/8r8adqF.png) 708 | 709 | ### 設定時區 710 | 711 | Manage Jenkins -> Tools and Actions -> Script Console 712 | 713 | 直接執行以下的指令 714 | 715 | ```cmd 716 | System.setProperty('user.timezone', 'Asia/Taipei') 717 | ``` 718 | 719 | Manage Jenkins -> Status Information -> System Information 720 | 721 | ![alt tag](https://i.imgur.com/mh5Touq.png) 722 | 723 | Manage Jenkins -> Manage Users -> 選擇 user -> User Defined Time Zone 724 | 725 | ![alt tag](https://i.imgur.com/byNu4JT.png) 726 | 727 | ### 設定權限 Security 728 | 729 | 之後到 Manage Jenkins -> Security -> Configure Global Security, 730 | 731 | 找到 Authorization 之後選擇 Project-based Matrix Authorization Strategy 732 | 733 | 這個設定是依據專案分權限, 你可以依照自己的需求設定 734 | 735 | ![alt tag](https://i.imgur.com/aC0lr98.png) 736 | 737 | 然後因為你是選擇依照專案分權限, 738 | 739 | 你在 job 中的設定會多出 Enable project-based security, 740 | 741 | 可選擇是否繼承上面的 Security 設定, 742 | 743 | 也可以依照 user 設定 (像是這個專案只有誰可以看到這樣) 744 | 745 | ![alt tag](https://i.imgur.com/y35InG0.png) 746 | 747 | ## 後記: 748 | 749 | 這次和大家介紹 Jenkins,相信大家一定覺得 Jenkins 超棒 :heart_eyes: ,我也只介紹比較基本的功能,如果要全部介紹完, 750 | 751 | 要花好多時間 ( 默默研究中:sweat_smile: )。如果你是沒有導入CI 的團隊,我會建議先導入幾個重要的部份就好,整個流程不一 752 | 753 | 定要完全的複製到你們的團隊上,可以一小部分一小部分慢慢導入,這樣整個團隊的反彈也不會那麼大。 754 | 755 | 最後大家可以朝下面這張圖的目標前進 756 | 757 | ![](https://i.imgur.com/dCASBwT.png) 758 | 759 | 圖片來源 [https://chrisshayan.atlassian.net/wiki/spaces/my/blog/2013/07/23/4227074/Continuous+Delivery+Matrix](https://chrisshayan.atlassian.net/wiki/spaces/my/blog/2013/07/23/4227074/Continuous+Delivery+Matrix) 760 | 761 | ## 執行環境 762 | 763 | * Linux 764 | * Mac 765 | * Python 3.6.2 766 | * windows 10 767 | 768 | ## Reference 769 | 770 | * [https://docs.docker.com/](https://docs.docker.com/) 771 | * [docker jenkins](https://hub.docker.com/r/jenkins/jenkins) 772 | 773 | ## Donation 774 | 775 | 文章都是我自己研究內化後原創,如果有幫助到您,也想鼓勵我的話,歡迎請我喝一杯咖啡:laughing: 776 | 777 | ![alt tag](https://i.imgur.com/LRct9xa.png) 778 | 779 | [贊助者付款](https://payment.opay.tw/Broadcaster/Donate/9E47FDEF85ABE383A0F5FC6A218606F8) 780 | 781 | ## License 782 | 783 | MIT license 784 | -------------------------------------------------------------------------------- /jenkins_host/api/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.6.2 2 | LABEL maintainer twtrubiks 3 | ENV PYTHONUNBUFFERED 1 4 | RUN mkdir /docker_api 5 | WORKDIR /docker_api 6 | COPY requirements.txt . 7 | RUN pip install -r requirements.txt 8 | 9 | 10 | -------------------------------------------------------------------------------- /jenkins_host/api/requirements.txt: -------------------------------------------------------------------------------- 1 | django<2.0 2 | psycopg2 3 | djangorestframework 4 | -------------------------------------------------------------------------------- /jenkins_host/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.5' 2 | services: 3 | 4 | db: 5 | image: postgres 6 | environment: 7 | POSTGRES_PASSWORD: password123 8 | ports: 9 | - "5432:5432" 10 | volumes: 11 | - pgdata_jenkins_host:/var/lib/postgresql/data/ 12 | 13 | api: 14 | build: ./api 15 | restart: always 16 | command: python manage.py runserver 0.0.0.0:8000 17 | ports: 18 | - "8002:8000" 19 | volumes: 20 | - ./workspace/workspace/demo/api:/docker_api 21 | depends_on: 22 | - db 23 | 24 | jenkins: 25 | image: jenkins/jenkins:lts-jdk11 26 | restart: always 27 | environment: 28 | JAVA_OPTS: "-Djava.awt.headless=true -Xmx512m -Xms512m -Djava.util.logging.config.file=/var/jenkins_home/log.properties" 29 | ports: 30 | - "8080:8080" 31 | - "50000:50000" 32 | volumes: 33 | - ./workspace:/var/jenkins_home 34 | 35 | volumes: 36 | pgdata_jenkins_host: -------------------------------------------------------------------------------- /jenkins_nginx/README.md: -------------------------------------------------------------------------------- 1 | # docker-jenkins-nginx-tutorial 2 | 3 | Manage Jenkins -> Configure System -> Jenkins Location 4 | 5 | 請把 Jenkins URL 改成你的 URL 6 | 7 | (還沒搭 nginx 時, 應該會有 port, 請把 port 移除) 8 | 9 | ![alt tag](https://i.imgur.com/CoIdiaY.png) 10 | -------------------------------------------------------------------------------- /jenkins_nginx/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.5' 2 | services: 3 | 4 | nginx-proxy: 5 | image: jwilder/nginx-proxy:alpine 6 | restart: always 7 | container_name: nginx-proxy 8 | ports: 9 | - "80:80" 10 | - "443:443" 11 | volumes: 12 | - /var/run/docker.sock:/tmp/docker.sock:ro 13 | - html:/usr/share/nginx/html 14 | - dhparam:/etc/nginx/dhparam 15 | - vhost:/etc/nginx/vhost.d 16 | - certs:/etc/nginx/certs:ro 17 | networks: 18 | - proxy 19 | 20 | # nginx-proxy-letsencrypt: 21 | # image: jrcs/letsencrypt-nginx-proxy-companion 22 | # restart: always 23 | # depends_on: 24 | # - "nginx-proxy" 25 | # volumes: 26 | # - certs:/etc/nginx/certs 27 | # - vhost:/etc/nginx/vhost.d 28 | # - html:/usr/share/nginx/html 29 | # - /var/run/docker.sock:/var/run/docker.sock:ro 30 | # environment: 31 | # - ACME_CA_URI=https://acme-staging-v02.api.letsencrypt.org/directory 32 | # - NGINX_PROXY_CONTAINER=nginx-proxy 33 | # networks: 34 | # - proxy 35 | 36 | jenkins: 37 | image: jenkins/jenkins:lts-jdk11 38 | environment: 39 | JAVA_OPTS: "-Djava.awt.headless=true -Xmx512m -Xms512m -Djava.util.logging.config.file=/var/jenkins_home/log.properties" 40 | restart: always 41 | ports: 42 | - "50000" 43 | volumes: 44 | - jenkins_home:/var/jenkins_home 45 | environment: 46 | - VIRTUAL_HOST=127.0.0.1 # your server ip 47 | - VIRTUAL_NETWORK=nginx-proxy 48 | - VIRTUAL_PORT=8080 49 | networks: 50 | - proxy 51 | 52 | networks: 53 | proxy: 54 | name: self-nginx-proxy 55 | 56 | volumes: 57 | jenkins_home: 58 | certs: 59 | html: 60 | vhost: 61 | dhparam: 62 | -------------------------------------------------------------------------------- /jenkins_volume/api/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.6.2 2 | LABEL maintainer twtrubiks 3 | ENV PYTHONUNBUFFERED 1 4 | WORKDIR . 5 | COPY requirements.txt . 6 | RUN pip install -r requirements.txt 7 | 8 | -------------------------------------------------------------------------------- /jenkins_volume/api/requirements.txt: -------------------------------------------------------------------------------- 1 | django<2.0 2 | psycopg2 3 | djangorestframework 4 | -------------------------------------------------------------------------------- /jenkins_volume/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.5' 2 | services: 3 | 4 | db: 5 | image: postgres 6 | environment: 7 | POSTGRES_PASSWORD: password123 8 | ports: 9 | - "5432:5432" 10 | volumes: 11 | - pgdata_jenkins:/var/lib/postgresql/data/ 12 | 13 | api: 14 | build: ./api 15 | restart: always 16 | command: python /var/jenkins_home/workspace/demo/api/manage.py runserver 0.0.0.0:8000 17 | ports: 18 | - "8002:8000" 19 | volumes: 20 | - api_data:/docker_api 21 | - jenkins_data:/var/jenkins_home 22 | depends_on: 23 | - db 24 | 25 | jenkins: 26 | image: jenkins/jenkins:lts-jdk11 27 | restart: always 28 | environment: 29 | JAVA_OPTS: "-Djava.awt.headless=true -Xmx512m -Xms512m -Djava.util.logging.config.file=/var/jenkins_home/log.properties" 30 | ports: 31 | - "8080:8080" 32 | - "50000:50000" 33 | volumes: 34 | - jenkins_data:/var/jenkins_home 35 | volumes: 36 | api_data: 37 | jenkins_data: 38 | pgdata_jenkins: 39 | --------------------------------------------------------------------------------