---
# System prepended metadata

title: Docker and Kubernetes

---

# Docker and Kubernetes
# 為何使用Docker
![](https://i.imgur.com/XOazHhY.png)
![](https://i.imgur.com/vITyRSY.png)
![](https://i.imgur.com/Y2yAVL7.png)
# 什麼是Docker
![](https://i.imgur.com/UybC7Mn.png)
![](https://i.imgur.com/6dKZ7Yq.png)
# Docker Client and Docker Server
![](https://i.imgur.com/SxktcSx.png)
# 使用Docker Client
![](https://i.imgur.com/5NyLUZH.png)
# 什麼是Container
![](https://i.imgur.com/txk9y1t.png)
![](https://i.imgur.com/jh6ju7Y.png)
![](https://i.imgur.com/G8xggkd.png)
![](https://i.imgur.com/qL5c9K6.png)
![](https://i.imgur.com/UKcTgC5.png)
![](https://i.imgur.com/0CUUHIE.png)
![](https://i.imgur.com/Jd8zMwg.png)
# Namespacing and Control Groups並不屬於mac os或windows的，而是屬於linux的
![](https://i.imgur.com/j7NSL4R.png)
# 基本指令
![](https://i.imgur.com/NQRlhZz.png)
# Override Default Command
![](https://i.imgur.com/7mPBYaN.png)
![](https://i.imgur.com/eHQXpKi.png)

![](https://i.imgur.com/cpNC9RZ.png)
![](https://i.imgur.com/jjdKYs3.png)
# Command能不能使用取決於該image的system有沒有該程式能夠執行
![](https://i.imgur.com/ZbBd9aY.jpg)
# 查看containers
docker ps列出正在執行的container
docker ps --all列出包含曾經創建過的container
![](https://i.imgur.com/0Cr3rIo.png)
![](https://i.imgur.com/yvyTdbP.png)
# Container的生命週期
docker run = docker create + docker start -a
-a 表示顯示logs
![](https://i.imgur.com/dZXgFVP.png)
![](https://i.imgur.com/R9DURe4.png)
![](https://i.imgur.com/0vb82XT.jpg)

![](https://i.imgur.com/Iv9CZfG.png)
# 可以重啟之前的Container，但不能替換原本的Command
![](https://i.imgur.com/RNjKY8Q.png)
# 移除停止的Containers
![](https://i.imgur.com/02sTZpN.jpg)
# 查看Container的logs
![](https://i.imgur.com/YwnFcBh.png)
![](https://i.imgur.com/AbMWNDF.png)
# 停止Container
![](https://i.imgur.com/CJnJZNk.png)
SIGTERM = terminate signal
stop會通知程式停止，讓程式能夠根據自己寫的程式碼在自己停止之前執行備份之類的事，而kill則是直接強制停止程式，若執行stop後10秒程式仍未自己停止則會執行kill強制停止。
![](https://i.imgur.com/chTlMh4.png)
![](https://i.imgur.com/TjfTbGU.png)
![](https://i.imgur.com/CyZb0VU.png)
# 在Container執行多個Command
# 在執行中的Container執行Command
![](https://i.imgur.com/RX8RrE4.png)
![](https://i.imgur.com/X3p12A7.jpg)
# -it = -i -t
i表示連接STDIN t表示格式化輸出文字
![](https://i.imgur.com/yIqPkTZ.png)
# 在Container呼叫命令提示字元
離開為CTRL+D或輸入exit
![](https://i.imgur.com/lnXFBzr.png)
![](https://i.imgur.com/j1pdPp4.png)
# 啟動Container時開啟命令提示字元
![](https://i.imgur.com/oMPTT8p.png)
# 創建image
![](https://i.imgur.com/25pl9ez.png)
![](https://i.imgur.com/40DVLyu.png)
# 創建Dockerfile
![](https://i.imgur.com/LCblxSD.png)
```docker build .```
產生image ID

```docker run ${imageID}```
啟動container
![](https://i.imgur.com/gMLMikE.png)
# 每次執行一個instruction會產生暫存的image並刪除上一次暫存的image，然後每次執行下一個instruction會先用上次暫存的image啟動container再執行
![](https://i.imgur.com/t6aPfnN.png)

![](https://i.imgur.com/imKcfLy.png)

![](https://i.imgur.com/5fFl44y.png)
# Rebuild with Cache
因為build會根據是否有cache的關係，instruction的順序會影響找不到之前的cache而重新fetch建立新的image和container
![](https://i.imgur.com/U5lrNDj.png)
# Tagging an Image
傳統命名規範
![](https://i.imgur.com/G1Yz3ha.png)
# 技術上來說tag是指後面的version，前面dockerID/repo比較像專案名稱
# 若沒指定version預設為:latest
![](https://i.imgur.com/44WlaUQ.png)
# 啟動時若不指定版本則會拿最新或latest的
![](https://i.imgur.com/u9AruhS.png)
# Docker Commit for Windows
![](https://i.imgur.com/GrmS9sh.png)
# 用Docker Commit手動產生image
可以在執行中的docker中產生image
實務上不推薦使用，用Dockerfile就好，方便重啟
![](https://i.imgur.com/tmLTUNe.png)
image ID可以不用貼全部
![](https://i.imgur.com/uiTaPjQ.jpg)
# Docker with Node.js
![](https://i.imgur.com/GUKT1au.png)
# Port Mapping
只能在runtime指定，不能在Dockerfile指定
![](https://i.imgur.com/xPOwI4A.png)
![](https://i.imgur.com/wsAQOwm.png)
# 設定Working Directory
![](https://i.imgur.com/tZLTO3K.png)
![](https://i.imgur.com/MuSX5fx.png)
# 最小化Rebuild成本
若沒修改package.json在安裝套件階段(RUN npm install)就應該繼續使用原本的Cache來產生image
![](https://i.imgur.com/mgUXZjb.png)
# 多個container
![](https://i.imgur.com/NTvLchy.png)
# 若Node和Redis用同一個Container在以後擴展時會不方便
![](https://i.imgur.com/6DmrGjE.png)
# 因此將Redis分出來有自己的Container
![](https://i.imgur.com/YDSrwzm.png)
# Docker Compose
用Docker CLI設定網路那些太麻煩，指令太多，所以通常都用Docker Compose設定
![](https://i.imgur.com/T1PSRRS.png)
# 為了避免每次啟動都要輸入一堆Docker CLI，所以才用Docker Compose，另外也方便一次啟動多個Container和自動設定他們之間的連線
![](https://i.imgur.com/ctsp46t.png)
![](https://i.imgur.com/J0bRZfH.png)
![](https://i.imgur.com/VqclMwZ.png)
# version為docker-compose的格式版本，build表示使用Dockerfile建立image，-在yml中表示陣列
![](https://i.imgur.com/XANivEF.png)
# Difference between service and container in docker compose
https://stackoverflow.com/questions/35565770/difference-between-service-and-container-in-docker-compose
# 一個service可以由一個或多個container執行
![](https://i.imgur.com/TNLAHrV.png)
# Docker會將request出去的host檢查是否為Docker service name，若符合則request到該service container，Redis預設port為6379
![](https://i.imgur.com/8jEyPnB.jpg)
# Docker Compose Command
第一次若直接使用docker-compose run也會自動build
![](https://i.imgur.com/xg8iU37.png)
# 停止docker-compose
![](https://i.imgur.com/qxZyFhc.png)
-d為在背景執行
-d=false: Detached mode: Run container in the background, print new container id
# 處理container crash
模擬crash
![](https://i.imgur.com/27e9VLR.png)
# Status codes
除了0以外都是error code
![](https://i.imgur.com/o5H90XS.png)
# Restart Policies
unless-stopped為總是重啟除非在終端機手動輸入停止
no必須加雙引號或單引號告訴yaml為字串，因為no在yaml中為boolean的false
![](https://i.imgur.com/lS9rScw.png)
![](https://i.imgur.com/PrVEeMb.png)
# docker-compose ps
類似docker ps，但必須所在目錄要有docker-compose.yml檔案，會根據該檔案列出其中正在執行的container
# 開發工作流程
![](https://i.imgur.com/6UrZ6WT.png)
![](https://i.imgur.com/Y5ArTLj.png)
![](https://i.imgur.com/NBsNqTx.png)
![](https://i.imgur.com/MoF9L0Q.png)
# Docker的目的
![](https://i.imgur.com/zSelHsM.png)
# 用CRA建立react專案並新增Dockfile.dev用於dev環境，之後的Dockfile用於prod環境
![](https://i.imgur.com/y3nFQ2R.png)
# 指定Dockfile
```docker build -f ${fileName} .```
![](https://i.imgur.com/oWHpufY.png)
# 將不必要的node_modules刪除避免COPY，節省build的時間
# Docker Volumes
# 將本地的source code改為mapping reference的方式，避免每次檔案更動都要手動docker build和ducker run
![](https://i.imgur.com/Yvzapzn.png)
pwd = present working directory
# pwd在Windows的PowerShell沒有該指定，可以用git bash，但仍會有問題，所以改使用${PWD}在PowerShell上，並在package.json的scripts上新增WATCHPACK_POLLING=true 
![](https://i.imgur.com/4Chdb9D.png)
# 可以將WATCHPACK_POLLING=true移至docker-compose.yml(推薦)，不影響local的指令
![](https://i.imgur.com/Ys0LAwq.png)
# CHOKIDAR_USEPOLLING=true為舊版webpack變量，新版為WATCHPACK_POLLING=true
https://github.com/facebook/create-react-app/issues/10253#issuecomment-1127340307
![](https://i.imgur.com/i9Q5xDD.png)
# -v /app/node_modules不加:path代表不mapping到本地的node_modules，因為本地沒有node_modules
![](https://i.imgur.com/a8v7GWn.png)
# 用docker-compose簡化指令，且不再因為OS和CMD的關係遇到建立volumes的問題($(pwd) / ${PWD}那些)
因為build: .會去找Dockfille而不是Dockfile.dev
![](https://i.imgur.com/FcKu5HS.png)
context為image的目標位址，dockerfile為指定的Dockerfile檔案
![](https://i.imgur.com/b5qhPw2.png)
# 那Dockfile還需要COPY . .嗎?
如果用docker-compose的確是不必要的，但還是會建議留著，因為有可能之後不再用docker-compose改用原本的docker cli但忘記補上volume mounting，或留著當作提醒或參考
# test環境也能hot reload
不推薦的方法，要記指令和container ID
![](https://i.imgur.com/UhOqG8J.png)
# docker-compose也能使用ps拿到service name再exec，exec預設會自動帶-it
![](https://i.imgur.com/7QZGfAi.png)
推薦使用docker-compose
![](https://i.imgur.com/KO4z4jT.png)
# 目前遇到Windows無法自動reload App.test.js的問題，所以必須透過docker-compose exec web或tests npm run test的方式進去，每次App.test.js檔案有更動再按一次Enter更新，即使有加WATCHPACK_POLLING=true也沒用
# docker attach的是npm process(primary process)而不是start.js
![](https://i.imgur.com/V1mmN3r.png)

![](https://i.imgur.com/diJqiMO.jpg)
![](https://i.imgur.com/oCWlXOD.png)
# 也可以只建立web service就好，測試時也用web環境
# 建立prod service
![](https://i.imgur.com/TbfNDEK.png)
![](https://i.imgur.com/P9lnCbw.png)
# Multi-Step Docker Build Process
![](https://i.imgur.com/o7eS9Jb.png)
# as命名phase/stage name，每個FROM開頭都是一個phase/stage block，--from=phase或stage
![](https://i.imgur.com/oQuQVUN.png)
# nginx預設port是80，-d為在背景執行
```docker build .```
```docker run -d -p 8080:80 ${imageId}```
![](https://i.imgur.com/Lh4XZpM.jpg)
# RUN、CMD、ENTRYPOINT的差別
![](https://i.imgur.com/PiZkhLE.png)
![](https://i.imgur.com/UEAJoqc.png)
# 為container命名
```docker run --name my-name busybox```
# Travis CI
因為現在Travis CI要收費，可以改用GitHub Actions
![](https://i.imgur.com/swPAeEL.png)
# -t為給image命名(docker build)，--name為給container命名(docker create/docker run)
![](https://i.imgur.com/O93q2UH.png)
# 新增.travis.yml
sudo: required是為了能夠執行docker build
![](https://i.imgur.com/a1vjEpk.png)
# script執行指令若回傳0以外的status code代表有錯
# npm run test -- --test產生測試覆蓋率
![](https://i.imgur.com/nYpFRM7.png)
# 為了能夠在npm run test後exit，所以不能使用預設的dev環境，否則將永遠不會exit並回傳status code，因此要指定為CI環境
# -e為設定環境變數
![](https://i.imgur.com/EPqTJZc.png)
# 建立AWS Elastic Beanstalk並新增docker-compose-dev.yml和修改docker-compose.yml
![](https://i.imgur.com/zKKZdy6.png)
![](https://i.imgur.com/BWU2xlg.png)
# Elastic Beanstalk有偵測流量變大自動幫我們scale擴展的優點
![](https://i.imgur.com/ozfSQ52.png)
![](https://i.imgur.com/9nsmZMS.png)
# 建立AWS Elastic Beanstalk也會自動建立AWS S3
![](https://i.imgur.com/LTeq1Qv.jpg)
# .travis.yml新增deploy config
![](https://i.imgur.com/SnlISEG.png)
region去Elastic Beanstalk查看URL
bucket_name為Elastic Beanstalk的S3名稱
bucket_path為Elastic Beanstalk的S3專案資料夾位置(第一次deploy才會建立)
# on指定master這個branch才觸發
![](https://i.imgur.com/AkxXz5D.png)
# GitHub Actions
![](https://i.imgur.com/EWWSYqG.png)
# 目前不需要上傳至Docker Hub，所以其實不需要run: docker login這行
```
name: Deploy Frontend
on:
  push:
    branches:
      - main
 
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - run: docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
      - run: docker build -t cygnetops/react-test -f Dockerfile.dev .
      - run: docker run -e CI=true cygnetops/react-test npm test
 
      - name: Generate deployment package
        run: zip -r deploy.zip . -x '*.git*'
 
      - name: Deploy to EB
        uses: einaregilsson/beanstalk-deploy@v18
        with:
          aws_access_key: ${{ secrets.AWS_ACCESS_KEY }}
          aws_secret_key: ${{ secrets.AWS_SECRET_KEY }}
          application_name: docker-gh
          environment_name: Dockergh-env
          existing_bucket_name: elasticbeanstalk-us-east-1-923445559289
          region: us-east-1
          version_label: ${{ github.sha }}
          deployment_package: deploy.zip
```
# 設定AWS KEY
# 去IAM新增user
![](https://i.imgur.com/HaoFsYj.png)
![](https://i.imgur.com/MqD5Sic.png)
![](https://i.imgur.com/laFkFMw.png)
![](https://i.imgur.com/D8XJYMx.png)
![](https://i.imgur.com/hNnOP0q.png)
![](https://i.imgur.com/mxKw4lo.png)
# 設定Travis CI環境變數
![](https://i.imgur.com/aALY6z0.png)
![](https://i.imgur.com/2dZr4L8.png)
# .travis.yml新增AWS KEY
![](https://i.imgur.com/q9qFdBn.png)
# Dockerfile補上EXPOSE port
![](https://i.imgur.com/9enpXQC.png)
# 停止使用Elastic Beanstalk
![](https://i.imgur.com/tpnicx3.png)
# 單個Container部屬問題
![](https://i.imgur.com/OkHFL6g.png)
# 用Fib計算機專案模擬多個Container情景
![](https://i.imgur.com/vp0GzYX.png)
![](https://i.imgur.com/sLXIV8L.png)
![](https://i.imgur.com/vGlCQya.png)
![](https://i.imgur.com/okvJdn6.png)
# 設定runtime環境變數
# runtime環境變數在build image還不會設定，要啟動container時才會
![](https://i.imgur.com/toHjlAz.png)
![](https://i.imgur.com/U7xZQXp.png)

![](https://i.imgur.com/zPKyzuK.png)
![](https://i.imgur.com/IjpXiaM.png)
# Nginx Path Routing
![](https://i.imgur.com/IeUD3Oe.png)
![](https://i.imgur.com/DeUiyKw.png)
# 新增nginx default.conf
# /etc/nginx/nginx.conf會include /etc/nginx/conf.d/*.conf
![](https://i.imgur.com/MBTZvGl.png)
# server屬於關鍵字，所以要將docker-compose的server也改名
![](https://i.imgur.com/oIQKUwN.png)

![](https://i.imgur.com/KZudL9A.png)
# 設定nginx監聽port、proxy_pass反向代理設定、rewrite path移除/api
![](https://i.imgur.com/dm8h0cz.png)
# 新增nginx Dockerfile
![](https://i.imgur.com/C7z14LG.png)
# docker-compose新增nginx
![](https://i.imgur.com/V2onRS5.png)
# 如果第一次docker-compose up --build啟動可能會有錯誤，某些container可能還在install所以連線失敗，重新docker-compose up就好
![](https://i.imgur.com/I2GrabC.png)
# dev websocket問題
![](https://i.imgur.com/Ux3skM8.png)
![](https://i.imgur.com/OChghSG.png)
![](https://i.imgur.com/zPO0E9d.png)
# prod CI
# 目的：減少每次部屬時在EB上重新build image的時間，將提前build好的image存到Docker Hub，以後改用其他除了EB以外的服務時也方便直接下載使用
![](https://i.imgur.com/F8skRYj.png)
![](https://i.imgur.com/c3MBwkL.png)
![](https://i.imgur.com/dUw30Lq.png)
![](https://i.imgur.com/eWLDYyD.png)
# prod的client nginx 預設的80 port改為3000
![](https://i.imgur.com/Sa62sQQ.png)
# 其實可以只需要一個nginx就好，但有可能你的react files不是使用nginx存放，而是其他簡單的file system data store，
![](https://i.imgur.com/l19ACDw.png)
# 新增client的nginx config
# 當有聲明監聽其他port時，會自動停用預設的80 port
# index指定root的網站初始頁
# try_files為抓取資源的優先順序，如果請求是/aaa/bbb，那會先去aaa資料夾找有沒有bbb這個檔案，沒有就找aaa/bbb資料夾有沒有index.html或.htm檔案，沒有就找/index.html
![](https://i.imgur.com/liRNOnG.png)
記得補上try_files $uri $uri/ /index.html
![](https://i.imgur.com/VJTL464.png)
# location、root、alias的差別
![](https://i.imgur.com/s27yog0.png)
# 新增client的Dockerfile，EXPOSE不再是80而是3000
![](https://i.imgur.com/vynUTbd.png)
# 先移除test，因為在測試時我們的後端不會啟動，實務上會用mockup資料替代
![](https://i.imgur.com/3B2x7cK.png)
# Travis prod config
![](https://i.imgur.com/bQElBs8.png)
# 新增.travis.yml
![](https://i.imgur.com/lmmI6a1.png)
# docker run lovebuizel/react-test npm test -- --cover改為docker run -e CI=true lovebuizel/react-test npm test
![](https://i.imgur.com/Awc3Eno.png)
```
sudo: required
services:
  - docker

before_install:
  - docker build -t lovebuizel/react-test -f ./client/Dockerfile.dev ./client

script:
  - docker run lovebuizel/react-test npm test -- --cover

after_success:
  -docker build -t lovebuizel/multi-client ./client
  -docker build -t lovebuizel/multi-nginx ./nginx
  -docker build -t lovebuizel/multi-server ./server
  -docker build -t lovebuizel/multi-worker ./worker
```
# 其實也可以在.travis.yml使用docker-compose
# 透過Docker CLI登入並將build完的image上傳至Docker Hub
![](https://i.imgur.com/GadZsyt.png)
```
sudo: required
services:
  - docker

before_install:
  - docker build -t lovebuizel/react-test -f ./client/Dockerfile.dev ./client

script:
  - docker run lovebuizel/react-test npm test -- --cover

after_success: -docker build -t lovebuizel/multi-client ./client
  -docker build -t lovebuizel/multi-nginx ./nginx
  -docker build -t lovebuizel/multi-server ./server
  -docker build -t lovebuizel/multi-worker ./worker
  # Log in to the docker CLI
  - echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_ID" --password-stdin
  # Take those images and push them to docker hub
  - docker push lovebuizel/multi-client
  - docker push lovebuizel/multi-nginx
  - docker push lovebuizel/multi-server
  - docker push lovebuizel/multi-worker
```
# 設定Travis環境變數
![](https://i.imgur.com/YpTY7H3.png)
# 使用GitHub Actions在prod環境
![](https://i.imgur.com/JIqzGRE.png)
# prod deploy in AWS
![](https://i.imgur.com/b5Lox0U.png)
# 之前因為只有一個Dockerfile，所以EB會自動幫我們build image和run image
![](https://i.imgur.com/VrogR9r.png)
# 但這次有多個資料夾，每個資料夾裡面有各自的Dockfile，EB不知道該怎麼處理
![](https://i.imgur.com/bjLa5xG.png)
# Dockerrun.aws.json告訴EB要去哪裡pull image和設定port mapping等相關資訊
![](https://i.imgur.com/J55pplo.png)
# docker-compose.yml和Dockerrun.aws.json類似，主要差別為前者如何build image，後者如何使用image
![](https://i.imgur.com/wxesGSw.png)
# EB其實不知道如何處理container，尤其是multi-container，實際上他會委派AWS的另一個服務Elastic Container Service(ECS)去處理，而ECS中的task definition，用於告訴ECS怎麼run single container，其格式又跟Dockerrun.aws.json幾乎一樣，所以可以當作文件參考
![](https://i.imgur.com/SBpnWmU.png)
![](https://i.imgur.com/JlG0lDA.jpg)
# 新增Dockerrun.aws.json
# name名稱無所謂
# hostname就跟docker-compose的services一樣，用於container間彼此的連接，所以server的hostname必須為api，但如果沒用到其實可以不用指定名稱，例如這裡的worker和nginx
# essential表示如果這個container掛掉是否要將其他container也一起關掉，必須至少要有一個為true，這裡選擇nginx container，因為網站如果掛掉那其他服務也沒用了
![](https://i.imgur.com/EyqhXhA.png)
# portMappings就跟docker-compose的ports一樣，映射本地與container的port
![](https://i.imgur.com/5LS82TN.png)
# Dockerrun.aws.json不像docker-compose可以直接使用services連接container，必須額外聲明，且是單向的，links填入的container名稱是前面指定的name
![](https://i.imgur.com/g2T7z7D.png)
# 新版EB平台不再使用Dockerrun.aws.json，而是docker-compose.yml
![](https://i.imgur.com/goAO2l7.png)
![](https://i.imgur.com/6u6IMe0.png)
# prod的redis和postgres建議使用其他服務，而不是自己建立container
![](https://i.imgur.com/3fXTsFo.png)
# 選擇其他服務的原因
以後遷移至EB以外的服務方便
![](https://i.imgur.com/7JGj9ey.png)
自動備份很重要
![](https://i.imgur.com/WrPprii.png)
# 預設AWS的服務不能彼此溝通，必須透過Virtual Private Cloud(VPC)的Security Group設定
![](https://i.imgur.com/FmnE8DR.png)
# 每個region都有預設的VPC
![](https://i.imgur.com/mGx21YO.png)
# 建立EB同時也會建立一個預設的Security Group套用上去
![](https://i.imgur.com/2OddKWl.png)
# Security Group也可以設定inbound、outbound等規則
![](https://i.imgur.com/SzM6IjX.png)
# 建立一個在相同Security Group內AWS service可以彼此溝通的規則並套用上去
![](https://i.imgur.com/GL52FSg.png)
# 建立AWS RDS
![](https://i.imgur.com/My4FF4y.png)
# 建立AWS ElastiCache Redis
![](https://i.imgur.com/hmkqyxM.png)
![](https://i.imgur.com/OAl9xLa.png)
![](https://i.imgur.com/XyfxxfX.png)
![](https://i.imgur.com/FxGeA3d.png)
# 建立Security Group
![](https://i.imgur.com/9ZfkH23.png)
![](https://i.imgur.com/9Hihzk3.png)
# 套用Security Group
![](https://i.imgur.com/2YHB1Zn.png)
![](https://i.imgur.com/W8OkcAy.png)
![](https://i.imgur.com/CLdbr2Z.png)
# 設定EB環境變數
![](https://i.imgur.com/XXOuQON.png)
DB使用者、DB密碼、DB名稱來自建立RDS時設定的
![](https://i.imgur.com/RkPQFH6.png)
Redis Endpoint
![](https://i.imgur.com/ji2Vggu.png)
RDS Endpoint
![](https://i.imgur.com/WdMQwIg.png)
# 新增AWS IAM user並設定Travis環境變數
![](https://i.imgur.com/4RdI6Qp.png)
![](https://i.imgur.com/oSxlKq2.png)
# .travis.yml新增deploy script
![](https://i.imgur.com/ZI3lepV.png)
![](https://i.imgur.com/ha2Bb2I.png)
# 分配Container記憶體容量
![](https://i.imgur.com/hkRdU6O.png)
# 實際要分配多久記憶體沒有一定標準，要自己研究，這裡全部指定為128MB
![](https://i.imgur.com/JPQi40K.png)
# docker-compose.yml的參數則為mem_limit: 128m
```
version: "3"
services:
  client:
    image: "lovebuizel/multi-client-10-14"
    mem_limit: 128m
    hostname: client
  server:
    image: "lovebuizel/multi-server-10-14"
    mem_limit: 128m
    hostname: api
    environment:
      - REDIS_HOST=$REDIS_HOST
      - REDIS_PORT=$REDIS_PORT
      - PGUSER=$PGUSER
      - PGHOST=$PGHOST
      - PGDATABASE=$PGDATABASE
      - PGPASSWORD=$PGPASSWORD
      - PGPORT=$PGPORT
  worker:
    image: "lovebuizel/multi-worker-10-14"
    mem_limit: 128m
    hostname: worker
    environment:
      - REDIS_HOST=$REDIS_HOST
      - REDIS_PORT=$REDIS_PORT
  nginx:
    image: "lovebuizel/multi-nginx-10-14"
    mem_limit: 128m
    hostname: nginx
    ports:
      - "80:80"
```
# 若有錯誤可以去Log查看
![](https://i.imgur.com/NkFR1V0.png)
# 什麼是Kubernetes和為何使用
![](https://i.imgur.com/5HRth8H.png)
# 方便擴展或是你的應用程式需要run不同的Container
# EB預設的擴展策略，我們無法控制彼此的container group，且無法有效地將資源放在需要的地方
![](https://i.imgur.com/wJakefK.png)
希望變成
![](https://i.imgur.com/FrWDf94.png)
# Cluster為Master(負責控制每個Node)+一個或多個Nodes
# Node可以是VM或實體電腦，每個Node可以有一個或多個Container，且image可以不同
![](https://i.imgur.com/Fbk4Ncv.png)
# minikube只有在dev環境會用到，初學者在prod建議使用其他服務方便管理也比較安全
![](https://i.imgur.com/4q2CuGe.png)
# kubectl負責管理Node和其裡面Container，minikube目的就只有在本地建立和執行Kubernetes Cluster
![](https://i.imgur.com/OIcnl7D.png)
# 安裝Kubernetes不像安裝Docker一樣會自動幫你安裝其他相關的軟體，所以你還要安裝其他的東西
![](https://i.imgur.com/SJFPZ9T.png)
# macOS安裝Docker Desktop內建的Kubernetes
![](https://i.imgur.com/zwSvC8l.png)
![](https://i.imgur.com/oIlDvTX.png)
![](https://i.imgur.com/scOpICI.png)
# Windows安裝Docker Desktop內建的Kubernetes
![](https://i.imgur.com/2bYQcV8.png)
![](https://i.imgur.com/Z4nCeMn.png)
![](https://i.imgur.com/SKcTfl8.png)
# macOS安裝Minikube
![](https://i.imgur.com/jrmIQca.png)
![](https://i.imgur.com/i1CrLWJ.png)
# Windows應該使用Docker Desktop內建的Kubernetes而不是Minikube，因為VM驅動需要的virtualization會和WSL2衝突
![](https://i.imgur.com/jJC9xkv.png)
# macOS安裝Minikube
![](https://i.imgur.com/iR1ABjU.png)
![](https://i.imgur.com/FeQgXIL.png)
# 將之前的multi-client專案用container跑在本地的Kubernetes Cluster上
![](https://i.imgur.com/C6xtymp.png)
![](https://i.imgur.com/1AayXyY.png)
![](https://i.imgur.com/AzOaERc.png)
# 錯誤提醒
![](https://i.imgur.com/Z4Ea7SP.png)
# 新開專案並建立兩個config file
# k8s是Kubernetes的縮寫，意旨k和s之間有8個字母
# client-pod.yaml
![](https://i.imgur.com/CAuy0oS.png)
# client-node-port.yaml
![](https://i.imgur.com/Lyq89y6.png)
# 會將config file透過kubectl轉成k8s cluster裡的object
# object有各種不同的type(config file裡的kind)負責不同的工作，例如pod負責run container、servicce負責網路設定
![](https://i.imgur.com/zXnA2hP.png)
# 不同apiVersion能使用的object types也不同
![](https://i.imgur.com/sdjTeVm.png)
# Minikube會在你電腦建立VM(node)
![](https://i.imgur.com/8hhXcnb.png)
# 必須在pod裡面才能執行container，pod為一個container group，可以有一個或多個container，目的是將高度相關或必須一起執行才有意義的container放在一起，例如以下的support containers
# 每個Node可以有多個Pod
![](https://i.imgur.com/ZMOfQZv.png)
# metadata的name主要用於查看log時方便辨認的，labels則為selector尋找指定的service用的，component: web也可改叫tier: frontend，只要labels和selector一樣就好
# Service又有四種subtype，在prod不太會用NodePort，因為不希望port為30000~32767，除非遇到少數情況
![](https://i.imgur.com/SKedGbm.png)
# Node內建kube-proxy程式，是Node對外唯一的接口，負責決定request要傳到哪個Service，NodePort負責expose container的port
![](https://i.imgur.com/3T4mMZL.png)
![](https://i.imgur.com/pVvuSmS.png)
# port為其他pod之間溝通用(目前可以忽略)，targetPort為mapping指定的pod與外界的nodePort(port只能在30000~32767之間)，若沒指定nodePort則會隨機指派30000~32767之間的port
![](https://i.imgur.com/KKspvgG.png)
# 套用config file
![](https://i.imgur.com/dGaQbn9.png)
# 查看所有pod的狀態，預設為default namespace的pod，除非加--all-namespaces，另外查看namespace為kebuctl get ns
![](https://i.imgur.com/is8IGYC.png)
# READY左邊為正在runnung的pod數量，右邊為總共pod需要的數量
![](https://i.imgur.com/5hnUSXB.png)
# 查看所有service的狀態
![](https://i.imgur.com/6r3rD7P.png)
# PORT(S)的第一個為NodePort Service的port，第二個為nodePort，targetPort單純不重要所以不顯示
![](https://i.imgur.com/rerslTh.png)
# minikube建立的VM不能使用localhost訪問，要用minikube ip查詢的ip，若使用Docker Desktop則可以直接使用localhost
![](https://i.imgur.com/KM0PrIN.png)
# kube-apiserver有4個程式，目的是負責確保node運作正常
# config file只會傳到master，master會自動分配哪些node要執行哪些container，那些node的docker會去docker hub抓image存到自己的環境並建立container
# master有responsibility list可以確認監控到的狀態，若刪掉container會自己重啟該container
![](https://i.imgur.com/WCFXIYE.png)
![](https://i.imgur.com/Zp2fhkJ.png)
# k8s有兩種開發方法，Imperative和Declarative
![](https://i.imgur.com/GXmuasg.png)
# Imperative比較麻煩，一般開發和正式環境都不推薦
![](https://i.imgur.com/uau3wGH.png)
# Declarative只要將目標狀態寫在config file重新送給master就好
![](https://i.imgur.com/kMLIGi4.png)
# 只要知道有些部落格或文件的教學是用Imperative，建議改成Declarative使用
![](https://i.imgur.com/Sd1QNhH.png)
# 更新pod使用的image
![](https://i.imgur.com/hHM3P8C.png)
![](https://i.imgur.com/9ocQdEv.png)
# Master透過Name和Kind知道要更新原本Pod的image，而不是新建一個Pod
![](https://i.imgur.com/N24BUxd.png)
# kubectl describe查看詳細狀態
![](https://i.imgur.com/AAAbNEr.png)
# object name可以不指定
![](https://i.imgur.com/DL4fcHw.png)
![](https://i.imgur.com/u88FaYS.png)
# 更改port後重新apply卻報錯
![](https://i.imgur.com/CLqgx1p.jpg)
# pod config有些屬性是不能更新的，必須砍掉pod重建
![](https://i.imgur.com/bIKCIes.png)
# Object Type由Pods改用Deployment
![](https://i.imgur.com/08GNRqf.png)
# Deployment會監測和自動更新pod，所以適合dev和prod環境
# Pod執行一組container(container可以一個或多個)，而Deployment執行一組相同的pod(pod可以一個或多個)
# Pod因為更新不方便，所以只適合一次性的開發用，但仍然不適合正式環境使用
![](https://i.imgur.com/eUVr2gi.png)
# 透過Deployment裡的Pod Template建立及更新Pod
![](https://i.imgur.com/WLZS1cH.png)
# 建立Deployment config file
![](https://i.imgur.com/f7ilucI.png)
# replicas代表pod數量，template就跟先前的Pod config類似，Deployment並不會直接建立Pod，而是拿config叫Master建立，所以還需要selector matchLabels跟Master說要handle那些Pod，template的pod labels可以有多個，所以可能有selector matchLabels不需要handle全部pod的情況
![](https://i.imgur.com/ygCaATq.png)
# kubectl delete會根據config file裡的kind和name去刪除pod，會需要可能10秒的時間，如同之前刪除container一樣
![](https://i.imgur.com/FIHzd5V.png)
![](https://i.imgur.com/Eptjh96.jpg)
# DESIRED為需要的pod數量、CURRENT為目前的pod數量、當apply config file更新時會將全部存在的pod設為out of date，等到pod更新或重建才會改成UP-TO-DATE，AVAILABLE代表成功啟動container或已準備好的pod數量
![](https://i.imgur.com/klZoFnk.png)
# 新版改成READY
![](https://i.imgur.com/wmd7pEB.png)
# -o wide等於--output=wide，用來查看更多的資訊
![](https://i.imgur.com/jBGUfSK.png)
# Service讓你不用管因為更新或新建pod而改變的ip是什麼，自動幫你mapping
![](https://i.imgur.com/h3qz7GO.png)
# 如何確保k8s使用的image是最新的
# 本地重新build image並push上docker hub
![](https://i.imgur.com/DMaR5CC.png)
![](https://i.imgur.com/OOFQoHO.png)
# 要確保k8s使用的image是最新的是很難的事情，目前沒有好方法，只能選比較不差的方法(新版有kubectl rollout restart可以使用)
# 因為config file沒改動，apply會被拒絕，第一個因為有可能刪錯pod所以最不推薦，這裡選第三個方法
# 新版可以用kubectl rollout restart -f deployment.yml，會用直接新增pod的方式重啟container，期間舊的繼續運行，待新增完後再刪掉舊的pod，達到服務不中斷的效果
![](https://i.imgur.com/xk1PJDf.png)
![](https://i.imgur.com/fr5DLrN.png)
![](https://i.imgur.com/6QjVAVz.png)
# kubectl set
![](https://i.imgur.com/LFX7rfl.png)
![](https://i.imgur.com/6zwcXeZ.png)
![](https://i.imgur.com/UegmjTm.png)
# 用Minikube的每次終端機要使用docker-client使令時都要將docker-server環境指定為k8s的Node，而不是預設的local docker for Mac/Windows
![](https://i.imgur.com/Cm1IGMX.png)
![](https://i.imgur.com/H9tQQEE.png)
![](https://i.imgur.com/XxHeEuY.png)
# 因為eval $(minikube docker-env)是暫時的，每個終端機視窗都是獨立的
![](https://i.imgur.com/8yoVpF1.png)
![](https://i.imgur.com/DREbnI6.png)
# 可以只記minikube docker-env就好，會有提示你eval $(minikube docker-env)
![](https://i.imgur.com/53oL8LH.png)
![](https://i.imgur.com/FDpoaRw.png)
![](https://i.imgur.com/snCd97c.png)
# 將multi-container專案應用在k8s上
![](https://i.imgur.com/CpHMaK8.png)
![](https://i.imgur.com/4xuSwZN.png)
# CTRL+C不等於docker-compose down，資料仍會保存
# 刪除nginx並新增k8s資料夾和config file
![](https://i.imgur.com/Ik3QOHO.png)
# 什麼是ClusterIP?和NodePort的區別差在NodePort expose pod到外網，而ClusterIP expose pod到內網，讓cluster內其他pod彼此可以溝通
![](https://i.imgur.com/mP4mkvp.png)
# 新增ClusterIP config file，屬性跟NodePort類似，但因為不用expose外網所以沒有nodePort屬性，port和targetPort可以不一樣，但目前沒有必要
![](https://i.imgur.com/zgukZ8E.png)
# kubectl delete deployment
![](https://i.imgur.com/OJKpakz.png)
# kubectl delete service
![](https://i.imgur.com/NBEShQc.png)
# kubectl apply -f 資料夾名稱 可以apply該資料夾的全部config file
# 新增multi-server的deployment config file
![](https://i.imgur.com/LPhVrSk.png)
還缺少db和redis的連線設定
![](https://i.imgur.com/Kr1WX4F.png)
# 新增multi-server的ClusterIP config file
![](https://i.imgur.com/KWTXRR4.png)
# 將多個config file合併成一個config file，但不推薦，多個config file可以立馬知道有幾個object，也能更快找到該object的config
![](https://i.imgur.com/iCLymHO.png)
# 新增multi-worker的Deployment config file
# replicas設1就好之後會擴展出去，這裡不用expose container的port，因為沒有其他object會連進來worker，所以也不需要ClusterIP
還缺少redis連線設定
![](https://i.imgur.com/8Gd3DVt.png)
# 新增redis的Deployment和ClusterIP config file
![](https://i.imgur.com/WgrAUt0.png)
![](https://i.imgur.com/tiy7NBl.png)
![](https://i.imgur.com/7nR2JJW.png)
# 新增postgres的Deployment和ClusterIP config file
![](https://i.imgur.com/UidGwQY.png)
# replicas為1是防止DB同時寫入造成資料不一致的衝突
![](https://i.imgur.com/ja3LZQK.png)
![](https://i.imgur.com/X47p8AJ.png)
# Persistent Volume Claim(PVC)
![](https://i.imgur.com/JolhMjm.png)
# 防止DB pod掛掉重建後遺失資料，所以將資料存在Volume(Persistent Volume，PV)，透過PVC去設定config
![](https://i.imgur.com/PPunyQc.png)
![](https://i.imgur.com/3WRcy9J.png)
![](https://i.imgur.com/kiWh7Cq.png)
# Volume在Container和Kubernetes為不一樣的東西
![](https://i.imgur.com/ZAC2Zj8.png)
# Volume在k8s中為Pod層級，如果pod內container掛掉重啟，volume資料還會存在，但如果pod掛掉的話資料仍會遺失
![](https://i.imgur.com/zoge0Gf.png)
# 所以我們需要的是Persistent Volume Claim(PVC)和Persistent Volume(PV)，而不是Volume
![](https://i.imgur.com/voO4efi.png)
# Volume和Persistent Volume(PV)的差別，Volume只有container掛掉資料不會遺失，而PV不管是container還是pod掛掉資料都不會遺失
![](https://i.imgur.com/A7cMBfn.png)
# Persistent Volume Claim(PVC)和Persistent Volume(PV)的關係
# PVC就像是一個廣告牌，讓Pod config知道能有什麼儲存資源能用，若k8s當下有提前建好的資源則稱為靜態供應PV，需要再建立該資源則稱為動態供應PV
比喻
![](https://i.imgur.com/ausrQf3.png)
![](https://i.imgur.com/GqpTOsW.png)
![](https://i.imgur.com/yJS1jRv.png)
![](https://i.imgur.com/d8ciYKT.png)
換成PVC
![](https://i.imgur.com/eXIzTm5.png)
![](https://i.imgur.com/nUyAMIn.png)
# 新增PVC config file
![](https://i.imgur.com/NmZwXvP.png)
# accessModes的種類
![](https://i.imgur.com/lH12ZvF.png)
# PV存在哪裡
![](https://i.imgur.com/DkhP5qy.png)
# 預設PV位置為local，但如果k8s在其他雲端平台上，則該預設PV位置可能為該平台的其他Service，不過一般來說用預設也沒差，除非有想特別指定的位置
# 可以通過設定PVC config file的storageClassName指定PV的位置
![](https://i.imgur.com/Je10Zji.png)
# 查看PV位置
![](https://i.imgur.com/EFk2LjI.png)

![](https://i.imgur.com/fmhQYxc.png)

![](https://i.imgur.com/AJdAsq8.png)
# Pod template選擇創建時要使用哪個PVC作為volume，並指定container要使用哪個volume
# mountPath和subPatj為選擇該volume要存在哪裡，這裡作為DB back up用
![](https://i.imgur.com/7aCf51S.png)
# kubectl get pv或pvc，STATUS Bound代表正在使用
![](https://i.imgur.com/qNWi4x8.png)
# 設定環境變數
# 紅色host為該service的metadata name，黃色為普通的變數，密碼因為安全原因不能寫在config file裡，要另外設定
![](https://i.imgur.com/kDVxmzg.png)
# 沒有"http://"，只是要表示host為url
![](https://i.imgur.com/7fbrnto.png)
![](https://i.imgur.com/pqFdCd0.png)
![](https://i.imgur.com/y8pnyUS.png)
![](https://i.imgur.com/6sktPqe.png)
# Secrets object
![](https://i.imgur.com/jehcZfK.png)
# 因為安全關係我們不用config file的方式去建立Secrets，而是用imperative指令的方式去建，在dev和prod環境都一樣
# secret的種類大多是generic，其他可能會用到的有docker-registry、tls等等
# <secret_name>類似於object的metadata name
# --from-literal表示要儲存的密碼在指令的後面，而不是來自其他檔案
![](https://i.imgur.com/gsbf269.png)
# 因為設置了postgres的密碼而不再使用預設的，所以postgres deployment config要額外override default password
![](https://i.imgur.com/qnYoRZc.png)
# postgres deployment config中image為postgres時若環境變數有POSTGRES_PASSWORD(舊版為PGPASSWORD)，postgres會自動將該變數當成預設密碼
![](https://i.imgur.com/HXMwqJ7.png)
# valueFrom name為前面的<secret_name>
![](https://i.imgur.com/JVnRpX4.png)
![](https://i.imgur.com/7p1CKrS.png)
# env的port號要加單引號或雙引號改成字串，不然會報錯
# NodePort比較適合dev，所以prod改用Ingress
# LoadBalancer是舊的方法，現在建議改用Ingress
![](https://i.imgur.com/UY2yIjA.png)
# LoadBalancer只能導入一組特定的pod，另外k8s也會在背後聯繫cloud provider需要建立一個cluster外部他們自己設定的load balancer，並自動設定將流量導入cluster裡的load balancer service
![](https://i.imgur.com/Y5lwAAF.png)
![](https://i.imgur.com/ulBEBMJ.png)
# 這裡使用的是ingress-nginx，而不是kubernetes-ingress
![](https://i.imgur.com/EBpfOBm.png)
# 不同環境安裝ingress的方式可能不同
![](https://i.imgur.com/UimhBB4.png)
# Ingress和Deployment類似，都是負責將current state轉成desired state
![](https://i.imgur.com/1BUxPKQ.png)
![](https://i.imgur.com/CiTBfV2.png)
# Ingress和ingress-nginx有一點點不同
![](https://i.imgur.com/riPGfQZ.png)
![](https://i.imgur.com/6ta3kU7.png)
# Ingress-Nginx在GC上其實也會建Load Balancer，Ingress config會經由kubectl建立一個Deployment，裡面有nginx-controller建立的nginx pod，並建立一個Load Balancer依附在上，另外也會預設建立一個額外的deployment(裡面有default-backend pod)，用來檢測健康狀態，但在現實中會用express api server取代，讓要檢查健康狀態的request跑到multi-server
![](https://i.imgur.com/1wiKUJn.png)
# 為何不用自己客製的nginx而是ingress-nginx
![](https://i.imgur.com/4gLVGZC.png)
# ingress-nginx有很多額外好用的功能，例如Sticky Sessions，他會將訪問不經過ClusterIP(ClustrtIP仍存在)直接連到multi-client pod，且相同用戶的request都會連到相同的server，達到不因為server不同而無法辨識session的功能
![](https://i.imgur.com/UfmG9eG.png)
# ingress-nginx補充資料
![](https://i.imgur.com/4lw0KQw.png)
https://www.joyfulbikeshedding.com/blog/2018-03-26-studying-the-kubernetes-ingress-system.html
![](https://i.imgur.com/pZAHRuU.png)
![](https://i.imgur.com/oiWS8N4.png)
# 安裝ingress-nginx
https://kubernetes.github.io/ingress-nginx/deploy/#quick-start
![](https://i.imgur.com/ALxqUMb.png)
# 新增Ingress config file
# 預設minikube ip或docker desktop localhost的預設port為80或443
![](https://i.imgur.com/yUmvJCd.png)
![](https://i.imgur.com/7ltZMyv.png)
![](https://i.imgur.com/5fy58Zt.png)
```
apiVersion: networking.k8s.io/v1
# UPDATE API
kind: Ingress
metadata:
  name: ingress-service
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/use-regex: "true"
    # ADD ANNOTATION
    nginx.ingress.kubernetes.io/rewrite-target: /$1
    # UPDATE ANNOTATION
spec:
  rules:
    - http:
        paths:
          - path: /?(.*)
            # UPDATE PATH
            pathType: Prefix
            # ADD PATHTYPE
            backend:
              service:
                # UPDATE SERVICE FIELDS
                name: client-cluster-ip-service
                port:
                  number: 3000
          - path: /api/?(.*)
            # UPDATE PATH
            pathType: Prefix
            # ADD PATHTYPE
            backend:
              service:
                # UPDATE SERVICE FIELDS
                name: server-cluster-ip-service
                port:
                  number: 5000
```
# Minikube Dashboard
![](https://i.imgur.com/8IzyKcG.png)
# 在Dashboard上更新設定不會儲存
![](https://i.imgur.com/MmK16wc.png)
# Docker Desktop的Kubernetes Dashboard需要額外設定
![](https://i.imgur.com/K0Pj86Y.png)
![](https://i.imgur.com/hnuDmlj.png)
https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/#deploying-the-dashboard-ui
# 錯誤修正，將server-deployment的image stephengrider/multi-server改為cygnetops/multi-server-pgfix-5-11
![](https://i.imgur.com/mr7bEWW.png)
# 將k8s cluster上到prod正式環境
![](https://i.imgur.com/qHvE1Io.png)
# 為何選擇Google Cloud而不是AWS
![](https://i.imgur.com/ygd8tbj.png)
# Google Kubernetes Engine(GKE)
# 要注意建立Cluster後就開始計算付費了
![](https://i.imgur.com/XCI2e7V.png)
![](https://i.imgur.com/N1BO8oG.png)
# Travis config file
![](https://i.imgur.com/3TRYjri.png)
# 去IAM建立Service Account並下載private key json
![](https://i.imgur.com/Rc5m9lo.png)
![](https://i.imgur.com/il02sRK.png)
![](https://i.imgur.com/RKCkmvW.png)
![](https://i.imgur.com/9YQqXWU.png)
# Ruby Version Fix
![](https://i.imgur.com/Oubvzvh.png)
# 需要Travis CLI將service account file加密再上傳，但Travis CLI需要ruby的環境(只有mac內建)，所以使用Ruby image的Docker來達成，就不用再local處理環境的問題
![](https://i.imgur.com/doYUpRC.png)
![](https://i.imgur.com/S3MNMZ6.png)
![](https://i.imgur.com/TaeNGlx.png)
# --no-rdoc --no-ri為可選，代表不要安裝document，讓安裝速度更快，ruby 2.4版後就不再需要了
# 因為需要build native extensions，所以不能使用ruby的alpine之類的版本，否則會build失敗
![](https://i.imgur.com/vXRUbuw.jpg)
# travis login github改用Personal Token
![](https://i.imgur.com/wq0aF6s.png)
![](https://i.imgur.com/xhLv931.png)
# travis login
![](https://i.imgur.com/CZSgmjX.png)
# travis encrypt-file service-account.json(之前下載的service account file) -r ${使用者名稱/專案名稱}
![](https://i.imgur.com/jef7WsF.jpg)
# 添加加密後提示的指令
![](https://i.imgur.com/gQwgHB8.png)
# 加密完要上傳前記得刪除原始下載的service account file
![](https://i.imgur.com/VrZNgsR.png)
# 更多Google Cloud CLI config，project後面為專案ID
![](https://i.imgur.com/UKpUigK.jpg)
![](https://i.imgur.com/JID5YiF.png)
![](https://i.imgur.com/nDUNrhQ.png)
# 之前有提到的錯誤修正
![](https://i.imgur.com/gH8UNii.png)
# 登入Docker並build image跑測試
![](https://i.imgur.com/9EfBng5.png)
# Custom Deployment Providers
# 因為沒有Travis內建的k8s provider，只能用script叫他執行自己另外寫的deploy.sh
![](https://i.imgur.com/QBkZAYg.png)
# 會遇到之前沒有強制更新latest image的問題，可以一樣用kubectl rollout restart deployments/server-deployment解決，另外覺得將build image和push image像之前一樣放在after_success比較好
![](https://i.imgur.com/Ofa8Xm3.png)
之前的寫法
![](https://i.imgur.com/vxwterW.png)
![](https://i.imgur.com/9fZJ8pe.png)
# 同之前不會抓最新image的問題，可以一樣用kubectl rollout restart deployments/server-deployment解決
![](https://i.imgur.com/z0WfYtw.png
# 這邊用添加git commit head的方法
![](https://i.imgur.com/0RF44fO.png)
# 用GIT_SHA也方便有問題時知道是哪個commit的版本，第一個build(push也要)有加tag latest(應該也可不加，因為預設是latest)，tag和push兩個版本同時將latest和該GIT_SHA更新，好讓之後用kubectl apply -f k8s時不用指定GIT_SHA也能抓到最新的版本
# k8s pull policy
https://kubernetes.io/docs/concepts/containers/images/#updating-images
![](https://i.imgur.com/vfKhtt2.png)
![](https://i.imgur.com/kFe6SNj.png)
# 添加Travis env
# CLOUDSDK_CORE_DISABLE_PROMPTS=1表示不要提示詢問
![](https://i.imgur.com/6DbsOUv.png)
deploy.sh file
```
docker build -t cygnetops/multi-client-k8s:latest -t cygnetops/multi-client-k8s:$SHA -f ./client/Dockerfile ./client
docker build -t cygnetops/multi-server-k8s-pgfix:latest -t cygnetops/multi-server-k8s-pgfix:$SHA -f ./server/Dockerfile ./server
docker build -t cygnetops/multi-worker-k8s:latest -t cygnetops/multi-worker-k8s:$SHA -f ./worker/Dockerfile ./worker

docker push cygnetops/multi-client-k8s:latest
docker push cygnetops/multi-server-k8s-pgfix:latest
docker push cygnetops/multi-worker-k8s:latest

docker push cygnetops/multi-client-k8s:$SHA
docker push cygnetops/multi-server-k8s-pgfix:$SHA
docker push cygnetops/multi-worker-k8s:$SHA

kubectl apply -f k8s
kubectl set image deployments/server-deployment server=cygnetops/multi-server-k8s-pgfix:$SHA
kubectl set image deployments/client-deployment client=cygnetops/multi-client-k8s:$SHA
kubectl set image deployments/worker-deployment worker=cygnetops/multi-worker-k8s:$SHA
```
# 在Google Console設定Google Cloud CLI
![](https://i.imgur.com/FLd8QrS.png)
# 為何需要再設定一次Google Cloud CLI
![](https://i.imgur.com/RJfvVUm.png)
![](https://i.imgur.com/sLUfb3U.png)
# 在Google Console設定Secret
![](https://i.imgur.com/mnVjpZC.png)
![](https://i.imgur.com/uTCe3fk.png)
# Helm(用來管理k8s中的套件)
![](https://i.imgur.com/hUXMT4C.png)
# 安裝Helm會安裝Helm CLI + Tiller Server(用來改變cluster config)
![](https://i.imgur.com/UES4ZIg.png)
# Role Based Access Control(RBAC)，用於規範誰有權限存取修改cluster的object，防止隨便一個pod都有權限修改刪除cluster
![](https://i.imgur.com/9nYOZBk.png)
# 預設local環境不會啟用RBAC，但Google Cloud預設會啟用
# 因為Tiller要修改cluster，所以需要額外設定Tiller的權限，建立有著ClusterRoleBinding的Service Accounts並指派給Tiller，要最保險也可以用RoleBinding
![](https://i.imgur.com/Eie584p.png)
![](https://i.imgur.com/BPkB9yM.png)
# Google Cloud安裝Helm之前先設定RBAC
![](https://i.imgur.com/qUP9HCV.png)
![](https://i.imgur.com/TQi80iG.png)
# 用Helm安裝ingress-nginx
![](https://i.imgur.com/qaclwKo.png)
![](https://i.imgur.com/pCiyVji.png)
![](https://i.imgur.com/3Ns7QbM.png)
![](https://i.imgur.com/oNV9yaq.png)
# Google Cloud內建的Load Balancer
![](https://i.imgur.com/0vQPypu.png)
![](https://i.imgur.com/kgzbjx9.png)
# 成功部屬
![](https://i.imgur.com/YNTC1XP.png)
![](https://i.imgur.com/MEtGatU.png)
# 使用HTTPS
![](https://i.imgur.com/vSdFMQX.png)
# 購買domain和設定
![](https://i.imgur.com/GML9Auu.png)
![](https://i.imgur.com/3MvG3EB.png)
![](https://i.imgur.com/FV5Rc54.png)
![](https://i.imgur.com/Vk6M0UF.png)
# 安裝Cert Manager
https://cert-manager.io/docs/installation/helm/#steps
![](https://i.imgur.com/Sqc0pGm.png)
# Cert Manager就像pod，而Certificate和Issuer為object，Issuer可以有多個
![](https://i.imgur.com/3T1jPhQ.png)
# Issuer config file
https://cert-manager.io/docs/configuration/acme/#creating-a-basic-acme-issuer
![](https://i.imgur.com/BalmXrg.png)
![](https://i.imgur.com/ooSdYXw.png)
# Certificate config file
![](https://i.imgur.com/UIWTzmC.png)
![](https://i.imgur.com/1HKUD3x.png)
![](https://i.imgur.com/c87Lpnt.png)
# 部屬後會看到certificates
![](https://i.imgur.com/Z4AlU2D.png)
![](https://i.imgur.com/dOzxTYe.png)
若看到這邊失敗沒關係
![](https://i.imgur.com/27649Fk.png)
Events才是重點
![](https://i.imgur.com/GGnBsif.png)
![](https://i.imgur.com/3zqnNtQ.png)
# Ingress config for HTTPS
![](https://i.imgur.com/PXjIq1o.png)
annotations新增cert manager和強制跳轉使用HTTPS
![](https://i.imgur.com/S9asqaC.png)
spec新增tls
![](https://i.imgur.com/ckt0cUj.png)
rules新增host並複製一份for www host
![](https://i.imgur.com/TOBBC06.png)
# 清理local環境
![](https://i.imgur.com/Vr8ro4S.png)
# local k8s開發無法像docker volume一樣自動即時更新，要重新rebuild image
# Skaffold有兩種模式可以達到自動即時更新的效果，第一種rebuild比較費時，第二種替換更新的檔案比較快(但要專案本來有hot reload的功能，例如這裡的CRA dev模式和nodemon)
![](https://i.imgur.com/VEBpBmr.png)
# 新增Skaffold config file
push false表示不要上傳image到docker hub或其他docker repository
artifacts為要管理的image，sync就是方法二，指定哪些檔案變動時要更新，除了這些檔案以外變動就會用方法一重新rebuild
![](https://i.imgur.com/im5vZNr.png)
![](https://i.imgur.com/GKM2kXm.png)
![](https://i.imgur.com/YBHWWLW.png)
# deploy為要管理的config file，執行skaffold dev時會apply
![](https://i.imgur.com/riJk0Uv.png)
# skaffold關掉時會自動刪除deploy中config file建立的pod，如果有要永久儲存資料的db或volume的話可以不將該config file放進去，以免skaffold關掉時delete該pod
![](https://i.imgur.com/hDw1oBw.png)
# artifacts補上需要管理的image
![](https://i.imgur.com/cXRZ8b3.png)
