# 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)