# Docker and Kubernetes # 為何使用Docker    # 什麼是Docker   # Docker Client and Docker Server  # 使用Docker Client  # 什麼是Container        # Namespacing and Control Groups並不屬於mac os或windows的,而是屬於linux的  # 基本指令  # Override Default Command     # Command能不能使用取決於該image的system有沒有該程式能夠執行  # 查看containers docker ps列出正在執行的container docker ps --all列出包含曾經創建過的container   # Container的生命週期 docker run = docker create + docker start -a -a 表示顯示logs     # 可以重啟之前的Container,但不能替換原本的Command  # 移除停止的Containers  # 查看Container的logs   # 停止Container  SIGTERM = terminate signal stop會通知程式停止,讓程式能夠根據自己寫的程式碼在自己停止之前執行備份之類的事,而kill則是直接強制停止程式,若執行stop後10秒程式仍未自己停止則會執行kill強制停止。    # 在Container執行多個Command # 在執行中的Container執行Command   # -it = -i -t i表示連接STDIN t表示格式化輸出文字  # 在Container呼叫命令提示字元 離開為CTRL+D或輸入exit   # 啟動Container時開啟命令提示字元  # 創建image   # 創建Dockerfile  ```docker build .``` 產生image ID ```docker run ${imageID}``` 啟動container  # 每次執行一個instruction會產生暫存的image並刪除上一次暫存的image,然後每次執行下一個instruction會先用上次暫存的image啟動container再執行    # Rebuild with Cache 因為build會根據是否有cache的關係,instruction的順序會影響找不到之前的cache而重新fetch建立新的image和container  # Tagging an Image 傳統命名規範  # 技術上來說tag是指後面的version,前面dockerID/repo比較像專案名稱 # 若沒指定version預設為:latest  # 啟動時若不指定版本則會拿最新或latest的  # Docker Commit for Windows  # 用Docker Commit手動產生image 可以在執行中的docker中產生image 實務上不推薦使用,用Dockerfile就好,方便重啟  image ID可以不用貼全部  # Docker with Node.js  # Port Mapping 只能在runtime指定,不能在Dockerfile指定   # 設定Working Directory   # 最小化Rebuild成本 若沒修改package.json在安裝套件階段(RUN npm install)就應該繼續使用原本的Cache來產生image  # 多個container  # 若Node和Redis用同一個Container在以後擴展時會不方便  # 因此將Redis分出來有自己的Container  # Docker Compose 用Docker CLI設定網路那些太麻煩,指令太多,所以通常都用Docker Compose設定  # 為了避免每次啟動都要輸入一堆Docker CLI,所以才用Docker Compose,另外也方便一次啟動多個Container和自動設定他們之間的連線    # version為docker-compose的格式版本,build表示使用Dockerfile建立image,-在yml中表示陣列  # Difference between service and container in docker compose https://stackoverflow.com/questions/35565770/difference-between-service-and-container-in-docker-compose # 一個service可以由一個或多個container執行  # Docker會將request出去的host檢查是否為Docker service name,若符合則request到該service container,Redis預設port為6379  # Docker Compose Command 第一次若直接使用docker-compose run也會自動build  # 停止docker-compose  -d為在背景執行 -d=false: Detached mode: Run container in the background, print new container id # 處理container crash 模擬crash  # Status codes 除了0以外都是error code  # Restart Policies unless-stopped為總是重啟除非在終端機手動輸入停止 no必須加雙引號或單引號告訴yaml為字串,因為no在yaml中為boolean的false   # docker-compose ps 類似docker ps,但必須所在目錄要有docker-compose.yml檔案,會根據該檔案列出其中正在執行的container # 開發工作流程     # Docker的目的  # 用CRA建立react專案並新增Dockfile.dev用於dev環境,之後的Dockfile用於prod環境  # 指定Dockfile ```docker build -f ${fileName} .```  # 將不必要的node_modules刪除避免COPY,節省build的時間 # Docker Volumes # 將本地的source code改為mapping reference的方式,避免每次檔案更動都要手動docker build和ducker run  pwd = present working directory # pwd在Windows的PowerShell沒有該指定,可以用git bash,但仍會有問題,所以改使用${PWD}在PowerShell上,並在package.json的scripts上新增WATCHPACK_POLLING=true  # 可以將WATCHPACK_POLLING=true移至docker-compose.yml(推薦),不影響local的指令  # CHOKIDAR_USEPOLLING=true為舊版webpack變量,新版為WATCHPACK_POLLING=true https://github.com/facebook/create-react-app/issues/10253#issuecomment-1127340307  # -v /app/node_modules不加:path代表不mapping到本地的node_modules,因為本地沒有node_modules  # 用docker-compose簡化指令,且不再因為OS和CMD的關係遇到建立volumes的問題($(pwd) / ${PWD}那些) 因為build: .會去找Dockfille而不是Dockfile.dev  context為image的目標位址,dockerfile為指定的Dockerfile檔案  # 那Dockfile還需要COPY . .嗎? 如果用docker-compose的確是不必要的,但還是會建議留著,因為有可能之後不再用docker-compose改用原本的docker cli但忘記補上volume mounting,或留著當作提醒或參考 # test環境也能hot reload 不推薦的方法,要記指令和container ID  # docker-compose也能使用ps拿到service name再exec,exec預設會自動帶-it  推薦使用docker-compose  # 目前遇到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    # 也可以只建立web service就好,測試時也用web環境 # 建立prod service   # Multi-Step Docker Build Process  # as命名phase/stage name,每個FROM開頭都是一個phase/stage block,--from=phase或stage  # nginx預設port是80,-d為在背景執行 ```docker build .``` ```docker run -d -p 8080:80 ${imageId}```  # RUN、CMD、ENTRYPOINT的差別   # 為container命名 ```docker run --name my-name busybox``` # Travis CI 因為現在Travis CI要收費,可以改用GitHub Actions  # -t為給image命名(docker build),--name為給container命名(docker create/docker run)  # 新增.travis.yml sudo: required是為了能夠執行docker build  # script執行指令若回傳0以外的status code代表有錯 # npm run test -- --test產生測試覆蓋率  # 為了能夠在npm run test後exit,所以不能使用預設的dev環境,否則將永遠不會exit並回傳status code,因此要指定為CI環境 # -e為設定環境變數  # 建立AWS Elastic Beanstalk並新增docker-compose-dev.yml和修改docker-compose.yml   # Elastic Beanstalk有偵測流量變大自動幫我們scale擴展的優點   # 建立AWS Elastic Beanstalk也會自動建立AWS S3  # .travis.yml新增deploy config  region去Elastic Beanstalk查看URL bucket_name為Elastic Beanstalk的S3名稱 bucket_path為Elastic Beanstalk的S3專案資料夾位置(第一次deploy才會建立) # on指定master這個branch才觸發  # GitHub Actions  # 目前不需要上傳至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       # 設定Travis CI環境變數   # .travis.yml新增AWS KEY  # Dockerfile補上EXPOSE port  # 停止使用Elastic Beanstalk  # 單個Container部屬問題  # 用Fib計算機專案模擬多個Container情景     # 設定runtime環境變數 # runtime環境變數在build image還不會設定,要啟動container時才會     # Nginx Path Routing   # 新增nginx default.conf # /etc/nginx/nginx.conf會include /etc/nginx/conf.d/*.conf  # server屬於關鍵字,所以要將docker-compose的server也改名   # 設定nginx監聽port、proxy_pass反向代理設定、rewrite path移除/api  # 新增nginx Dockerfile  # docker-compose新增nginx  # 如果第一次docker-compose up --build啟動可能會有錯誤,某些container可能還在install所以連線失敗,重新docker-compose up就好  # dev websocket問題    # prod CI # 目的:減少每次部屬時在EB上重新build image的時間,將提前build好的image存到Docker Hub,以後改用其他除了EB以外的服務時也方便直接下載使用     # prod的client nginx 預設的80 port改為3000  # 其實可以只需要一個nginx就好,但有可能你的react files不是使用nginx存放,而是其他簡單的file system data store,  # 新增client的nginx config # 當有聲明監聽其他port時,會自動停用預設的80 port # index指定root的網站初始頁 # try_files為抓取資源的優先順序,如果請求是/aaa/bbb,那會先去aaa資料夾找有沒有bbb這個檔案,沒有就找aaa/bbb資料夾有沒有index.html或.htm檔案,沒有就找/index.html  記得補上try_files $uri $uri/ /index.html  # location、root、alias的差別  # 新增client的Dockerfile,EXPOSE不再是80而是3000  # 先移除test,因為在測試時我們的後端不會啟動,實務上會用mockup資料替代  # Travis prod config  # 新增.travis.yml  # docker run lovebuizel/react-test npm test -- --cover改為docker run -e CI=true lovebuizel/react-test npm test  ``` 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  ``` 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環境變數  # 使用GitHub Actions在prod環境  # prod deploy in AWS  # 之前因為只有一個Dockerfile,所以EB會自動幫我們build image和run image  # 但這次有多個資料夾,每個資料夾裡面有各自的Dockfile,EB不知道該怎麼處理  # Dockerrun.aws.json告訴EB要去哪裡pull image和設定port mapping等相關資訊  # docker-compose.yml和Dockerrun.aws.json類似,主要差別為前者如何build image,後者如何使用image  # EB其實不知道如何處理container,尤其是multi-container,實際上他會委派AWS的另一個服務Elastic Container Service(ECS)去處理,而ECS中的task definition,用於告訴ECS怎麼run single container,其格式又跟Dockerrun.aws.json幾乎一樣,所以可以當作文件參考   # 新增Dockerrun.aws.json # name名稱無所謂 # hostname就跟docker-compose的services一樣,用於container間彼此的連接,所以server的hostname必須為api,但如果沒用到其實可以不用指定名稱,例如這裡的worker和nginx # essential表示如果這個container掛掉是否要將其他container也一起關掉,必須至少要有一個為true,這裡選擇nginx container,因為網站如果掛掉那其他服務也沒用了  # portMappings就跟docker-compose的ports一樣,映射本地與container的port  # Dockerrun.aws.json不像docker-compose可以直接使用services連接container,必須額外聲明,且是單向的,links填入的container名稱是前面指定的name  # 新版EB平台不再使用Dockerrun.aws.json,而是docker-compose.yml   # prod的redis和postgres建議使用其他服務,而不是自己建立container  # 選擇其他服務的原因 以後遷移至EB以外的服務方便  自動備份很重要  # 預設AWS的服務不能彼此溝通,必須透過Virtual Private Cloud(VPC)的Security Group設定  # 每個region都有預設的VPC  # 建立EB同時也會建立一個預設的Security Group套用上去  # Security Group也可以設定inbound、outbound等規則  # 建立一個在相同Security Group內AWS service可以彼此溝通的規則並套用上去  # 建立AWS RDS  # 建立AWS ElastiCache Redis     # 建立Security Group   # 套用Security Group    # 設定EB環境變數  DB使用者、DB密碼、DB名稱來自建立RDS時設定的  Redis Endpoint  RDS Endpoint  # 新增AWS IAM user並設定Travis環境變數   # .travis.yml新增deploy script   # 分配Container記憶體容量  # 實際要分配多久記憶體沒有一定標準,要自己研究,這裡全部指定為128MB  # 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查看  # 什麼是Kubernetes和為何使用  # 方便擴展或是你的應用程式需要run不同的Container # EB預設的擴展策略,我們無法控制彼此的container group,且無法有效地將資源放在需要的地方  希望變成  # Cluster為Master(負責控制每個Node)+一個或多個Nodes # Node可以是VM或實體電腦,每個Node可以有一個或多個Container,且image可以不同  # minikube只有在dev環境會用到,初學者在prod建議使用其他服務方便管理也比較安全  # kubectl負責管理Node和其裡面Container,minikube目的就只有在本地建立和執行Kubernetes Cluster  # 安裝Kubernetes不像安裝Docker一樣會自動幫你安裝其他相關的軟體,所以你還要安裝其他的東西  # macOS安裝Docker Desktop內建的Kubernetes    # Windows安裝Docker Desktop內建的Kubernetes    # macOS安裝Minikube   # Windows應該使用Docker Desktop內建的Kubernetes而不是Minikube,因為VM驅動需要的virtualization會和WSL2衝突  # macOS安裝Minikube   # 將之前的multi-client專案用container跑在本地的Kubernetes Cluster上    # 錯誤提醒  # 新開專案並建立兩個config file # k8s是Kubernetes的縮寫,意旨k和s之間有8個字母 # client-pod.yaml  # client-node-port.yaml  # 會將config file透過kubectl轉成k8s cluster裡的object # object有各種不同的type(config file裡的kind)負責不同的工作,例如pod負責run container、servicce負責網路設定  # 不同apiVersion能使用的object types也不同  # Minikube會在你電腦建立VM(node)  # 必須在pod裡面才能執行container,pod為一個container group,可以有一個或多個container,目的是將高度相關或必須一起執行才有意義的container放在一起,例如以下的support containers # 每個Node可以有多個Pod  # metadata的name主要用於查看log時方便辨認的,labels則為selector尋找指定的service用的,component: web也可改叫tier: frontend,只要labels和selector一樣就好 # Service又有四種subtype,在prod不太會用NodePort,因為不希望port為30000~32767,除非遇到少數情況  # Node內建kube-proxy程式,是Node對外唯一的接口,負責決定request要傳到哪個Service,NodePort負責expose container的port   # port為其他pod之間溝通用(目前可以忽略),targetPort為mapping指定的pod與外界的nodePort(port只能在30000~32767之間),若沒指定nodePort則會隨機指派30000~32767之間的port  # 套用config file  # 查看所有pod的狀態,預設為default namespace的pod,除非加--all-namespaces,另外查看namespace為kebuctl get ns  # READY左邊為正在runnung的pod數量,右邊為總共pod需要的數量  # 查看所有service的狀態  # PORT(S)的第一個為NodePort Service的port,第二個為nodePort,targetPort單純不重要所以不顯示  # minikube建立的VM不能使用localhost訪問,要用minikube ip查詢的ip,若使用Docker Desktop則可以直接使用localhost  # kube-apiserver有4個程式,目的是負責確保node運作正常 # config file只會傳到master,master會自動分配哪些node要執行哪些container,那些node的docker會去docker hub抓image存到自己的環境並建立container # master有responsibility list可以確認監控到的狀態,若刪掉container會自己重啟該container   # k8s有兩種開發方法,Imperative和Declarative  # Imperative比較麻煩,一般開發和正式環境都不推薦  # Declarative只要將目標狀態寫在config file重新送給master就好  # 只要知道有些部落格或文件的教學是用Imperative,建議改成Declarative使用  # 更新pod使用的image   # Master透過Name和Kind知道要更新原本Pod的image,而不是新建一個Pod  # kubectl describe查看詳細狀態  # object name可以不指定   # 更改port後重新apply卻報錯  # pod config有些屬性是不能更新的,必須砍掉pod重建  # Object Type由Pods改用Deployment  # Deployment會監測和自動更新pod,所以適合dev和prod環境 # Pod執行一組container(container可以一個或多個),而Deployment執行一組相同的pod(pod可以一個或多個) # Pod因為更新不方便,所以只適合一次性的開發用,但仍然不適合正式環境使用  # 透過Deployment裡的Pod Template建立及更新Pod  # 建立Deployment config file  # replicas代表pod數量,template就跟先前的Pod config類似,Deployment並不會直接建立Pod,而是拿config叫Master建立,所以還需要selector matchLabels跟Master說要handle那些Pod,template的pod labels可以有多個,所以可能有selector matchLabels不需要handle全部pod的情況  # kubectl delete會根據config file裡的kind和name去刪除pod,會需要可能10秒的時間,如同之前刪除container一樣   # DESIRED為需要的pod數量、CURRENT為目前的pod數量、當apply config file更新時會將全部存在的pod設為out of date,等到pod更新或重建才會改成UP-TO-DATE,AVAILABLE代表成功啟動container或已準備好的pod數量  # 新版改成READY  # -o wide等於--output=wide,用來查看更多的資訊  # Service讓你不用管因為更新或新建pod而改變的ip是什麼,自動幫你mapping  # 如何確保k8s使用的image是最新的 # 本地重新build image並push上docker hub   # 要確保k8s使用的image是最新的是很難的事情,目前沒有好方法,只能選比較不差的方法(新版有kubectl rollout restart可以使用) # 因為config file沒改動,apply會被拒絕,第一個因為有可能刪錯pod所以最不推薦,這裡選第三個方法 # 新版可以用kubectl rollout restart -f deployment.yml,會用直接新增pod的方式重啟container,期間舊的繼續運行,待新增完後再刪掉舊的pod,達到服務不中斷的效果    # kubectl set    # 用Minikube的每次終端機要使用docker-client使令時都要將docker-server環境指定為k8s的Node,而不是預設的local docker for Mac/Windows    # 因為eval $(minikube docker-env)是暫時的,每個終端機視窗都是獨立的   # 可以只記minikube docker-env就好,會有提示你eval $(minikube docker-env)    # 將multi-container專案應用在k8s上   # CTRL+C不等於docker-compose down,資料仍會保存 # 刪除nginx並新增k8s資料夾和config file  # 什麼是ClusterIP?和NodePort的區別差在NodePort expose pod到外網,而ClusterIP expose pod到內網,讓cluster內其他pod彼此可以溝通  # 新增ClusterIP config file,屬性跟NodePort類似,但因為不用expose外網所以沒有nodePort屬性,port和targetPort可以不一樣,但目前沒有必要  # kubectl delete deployment  # kubectl delete service  # kubectl apply -f 資料夾名稱 可以apply該資料夾的全部config file # 新增multi-server的deployment config file  還缺少db和redis的連線設定  # 新增multi-server的ClusterIP config file  # 將多個config file合併成一個config file,但不推薦,多個config file可以立馬知道有幾個object,也能更快找到該object的config  # 新增multi-worker的Deployment config file # replicas設1就好之後會擴展出去,這裡不用expose container的port,因為沒有其他object會連進來worker,所以也不需要ClusterIP 還缺少redis連線設定  # 新增redis的Deployment和ClusterIP config file    # 新增postgres的Deployment和ClusterIP config file  # replicas為1是防止DB同時寫入造成資料不一致的衝突   # Persistent Volume Claim(PVC)  # 防止DB pod掛掉重建後遺失資料,所以將資料存在Volume(Persistent Volume,PV),透過PVC去設定config    # Volume在Container和Kubernetes為不一樣的東西  # Volume在k8s中為Pod層級,如果pod內container掛掉重啟,volume資料還會存在,但如果pod掛掉的話資料仍會遺失  # 所以我們需要的是Persistent Volume Claim(PVC)和Persistent Volume(PV),而不是Volume  # Volume和Persistent Volume(PV)的差別,Volume只有container掛掉資料不會遺失,而PV不管是container還是pod掛掉資料都不會遺失  # Persistent Volume Claim(PVC)和Persistent Volume(PV)的關係 # PVC就像是一個廣告牌,讓Pod config知道能有什麼儲存資源能用,若k8s當下有提前建好的資源則稱為靜態供應PV,需要再建立該資源則稱為動態供應PV 比喻     換成PVC   # 新增PVC config file  # accessModes的種類  # PV存在哪裡  # 預設PV位置為local,但如果k8s在其他雲端平台上,則該預設PV位置可能為該平台的其他Service,不過一般來說用預設也沒差,除非有想特別指定的位置 # 可以通過設定PVC config file的storageClassName指定PV的位置  # 查看PV位置    # Pod template選擇創建時要使用哪個PVC作為volume,並指定container要使用哪個volume # mountPath和subPatj為選擇該volume要存在哪裡,這裡作為DB back up用  # kubectl get pv或pvc,STATUS Bound代表正在使用  # 設定環境變數 # 紅色host為該service的metadata name,黃色為普通的變數,密碼因為安全原因不能寫在config file裡,要另外設定  # 沒有"http://",只是要表示host為url     # Secrets object  # 因為安全關係我們不用config file的方式去建立Secrets,而是用imperative指令的方式去建,在dev和prod環境都一樣 # secret的種類大多是generic,其他可能會用到的有docker-registry、tls等等 # <secret_name>類似於object的metadata name # --from-literal表示要儲存的密碼在指令的後面,而不是來自其他檔案  # 因為設置了postgres的密碼而不再使用預設的,所以postgres deployment config要額外override default password  # postgres deployment config中image為postgres時若環境變數有POSTGRES_PASSWORD(舊版為PGPASSWORD),postgres會自動將該變數當成預設密碼  # valueFrom name為前面的<secret_name>   # env的port號要加單引號或雙引號改成字串,不然會報錯 # NodePort比較適合dev,所以prod改用Ingress # LoadBalancer是舊的方法,現在建議改用Ingress  # LoadBalancer只能導入一組特定的pod,另外k8s也會在背後聯繫cloud provider需要建立一個cluster外部他們自己設定的load balancer,並自動設定將流量導入cluster裡的load balancer service   # 這裡使用的是ingress-nginx,而不是kubernetes-ingress  # 不同環境安裝ingress的方式可能不同  # Ingress和Deployment類似,都是負責將current state轉成desired state   # Ingress和ingress-nginx有一點點不同   # 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  # 為何不用自己客製的nginx而是ingress-nginx  # ingress-nginx有很多額外好用的功能,例如Sticky Sessions,他會將訪問不經過ClusterIP(ClustrtIP仍存在)直接連到multi-client pod,且相同用戶的request都會連到相同的server,達到不因為server不同而無法辨識session的功能  # ingress-nginx補充資料  https://www.joyfulbikeshedding.com/blog/2018-03-26-studying-the-kubernetes-ingress-system.html   # 安裝ingress-nginx https://kubernetes.github.io/ingress-nginx/deploy/#quick-start  # 新增Ingress config file # 預設minikube ip或docker desktop localhost的預設port為80或443    ``` 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  # 在Dashboard上更新設定不會儲存  # Docker Desktop的Kubernetes Dashboard需要額外設定   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  # 將k8s cluster上到prod正式環境  # 為何選擇Google Cloud而不是AWS  # Google Kubernetes Engine(GKE) # 要注意建立Cluster後就開始計算付費了   # Travis config file  # 去IAM建立Service Account並下載private key json     # Ruby Version Fix  # 需要Travis CLI將service account file加密再上傳,但Travis CLI需要ruby的環境(只有mac內建),所以使用Ruby image的Docker來達成,就不用再local處理環境的問題    # --no-rdoc --no-ri為可選,代表不要安裝document,讓安裝速度更快,ruby 2.4版後就不再需要了 # 因為需要build native extensions,所以不能使用ruby的alpine之類的版本,否則會build失敗  # travis login github改用Personal Token   # travis login  # travis encrypt-file service-account.json(之前下載的service account file) -r ${使用者名稱/專案名稱}  # 添加加密後提示的指令  # 加密完要上傳前記得刪除原始下載的service account file  # 更多Google Cloud CLI config,project後面為專案ID    # 之前有提到的錯誤修正  # 登入Docker並build image跑測試  # Custom Deployment Providers # 因為沒有Travis內建的k8s provider,只能用script叫他執行自己另外寫的deploy.sh  # 會遇到之前沒有強制更新latest image的問題,可以一樣用kubectl rollout restart deployments/server-deployment解決,另外覺得將build image和push image像之前一樣放在after_success比較好  之前的寫法   # 同之前不會抓最新image的問題,可以一樣用kubectl rollout restart deployments/server-deployment解決  # 用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   # 添加Travis env # CLOUDSDK_CORE_DISABLE_PROMPTS=1表示不要提示詢問  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  # 為何需要再設定一次Google Cloud CLI   # 在Google Console設定Secret   # Helm(用來管理k8s中的套件)  # 安裝Helm會安裝Helm CLI + Tiller Server(用來改變cluster config)  # Role Based Access Control(RBAC),用於規範誰有權限存取修改cluster的object,防止隨便一個pod都有權限修改刪除cluster  # 預設local環境不會啟用RBAC,但Google Cloud預設會啟用 # 因為Tiller要修改cluster,所以需要額外設定Tiller的權限,建立有著ClusterRoleBinding的Service Accounts並指派給Tiller,要最保險也可以用RoleBinding   # Google Cloud安裝Helm之前先設定RBAC   # 用Helm安裝ingress-nginx     # Google Cloud內建的Load Balancer   # 成功部屬   # 使用HTTPS  # 購買domain和設定     # 安裝Cert Manager https://cert-manager.io/docs/installation/helm/#steps  # Cert Manager就像pod,而Certificate和Issuer為object,Issuer可以有多個  # Issuer config file https://cert-manager.io/docs/configuration/acme/#creating-a-basic-acme-issuer   # Certificate config file    # 部屬後會看到certificates   若看到這邊失敗沒關係  Events才是重點   # Ingress config for HTTPS  annotations新增cert manager和強制跳轉使用HTTPS  spec新增tls  rules新增host並複製一份for www host  # 清理local環境  # local k8s開發無法像docker volume一樣自動即時更新,要重新rebuild image # Skaffold有兩種模式可以達到自動即時更新的效果,第一種rebuild比較費時,第二種替換更新的檔案比較快(但要專案本來有hot reload的功能,例如這裡的CRA dev模式和nodemon)  # 新增Skaffold config file push false表示不要上傳image到docker hub或其他docker repository artifacts為要管理的image,sync就是方法二,指定哪些檔案變動時要更新,除了這些檔案以外變動就會用方法一重新rebuild    # deploy為要管理的config file,執行skaffold dev時會apply  # skaffold關掉時會自動刪除deploy中config file建立的pod,如果有要永久儲存資料的db或volume的話可以不將該config file放進去,以免skaffold關掉時delete該pod  # artifacts補上需要管理的image 
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up