1. 程式人生 > >kubernetes 權威指南學習筆記(2) -- 基本概念和術語

kubernetes 權威指南學習筆記(2) -- 基本概念和術語

基本概念和術語

Master&Node

Kubernetes 叢集的兩種管理角色: Master 和 Node

Master

Master 只的是叢集控制節點,每個叢集需要一個檢點來負責整個叢集的管理和控制。 基本上所有控制命令都發給它,它來負責具體的執行過程。

Master 節點通常會佔據一個獨立的伺服器。

Master 節點上執行著以下一組關鍵程序

  • Kubernetes API Server (kube-apiserver): 提供了HTTP Rest介面的關鍵服務程序,是Kubernetes裡所有資源的增、刪、改、查等操作的唯一入口,也是叢集控制的入口程序
  • Kubernetes Controller Manager(kube-controller-manager): Kubernetes 裡所有資源物件的自動化控制中心
  • Kubernetes Scheduler (kube-scheduler): 負責資源排程(Pod 排程) 的程序

Master 節點上還需要啟動一個etcd服務,k8s裡的所有資源物件的資料全部儲存在etcd中

Node

叢集中除了Master其他機器被稱為Node節點,Node可以是一臺物理機,也可以是一臺虛擬機器。Node是k8s叢集中工作負載節點,沒個Node會被Master分配一些工作負載(docker 容器), 當某個Node宕機時,其上的工作負載會被Master自動轉移到其他節點上去。

Node 節點執行以下一組關鍵程序

  • kubelet: 負責Pod對應的容器的建立、啟停等任務,同時與Master節點密切協作,實現叢集管理的基本功能
  • kube-proxy: 實現Kubernetes Service 的通訊與負載均衡機制的重要元件。
  • Docker Engine (docker): Docker 引擎,負責本機的容器建立和管理工作。

Node 可以在執行期間動態增加到Kubernetes叢集中,前提是節點已正確安裝、配置和啟動上述關鍵程序。

預設情況kubelet會向Master註冊自己, 這也是Kubernetes推薦的Node管理方式。

一旦Node納入叢集管理範圍,kubelet程序就會定時向Master節點回報自身的情報,如作業系統、Docker版本、機器的CPU和記憶體情況,以及當前有哪些Pod在執行。這樣Master可以獲知每個Node的資源使用情況,並實現高效均衡的資源排程策略。

某個Node超過指定時間不上報資訊,會被Master判定為“失聯”,Node的狀態被標記為不可用(Not Ready), 隨後Master會觸發“工作負載轉移”的自動流程。

Pod

構成

  • Pause 容器: 根容器
  • User 容器: 一個或多個緊密相關的使用者業務容器。

設計 Pause 原因:

  1. 以它的狀態代表整個容器組的狀態。
  2. Pod裡多個容器共享Pause容器的IP, 共享Pause容器掛接的Volume, 簡化容器通訊,檔案共享的問題。

Pod IP: k8s 為每個Pod 分配了唯一IP地址,Pod裡多個容器共享。

k8s要求底層網路支援叢集內任意兩個Pod之間的TCP/IP直接通訊,通常採用虛擬二層網路技術來實現,如 Flannel、Open vSwitch.

一個Pod裡的容器與另外主機上的Pod容器能夠直接通訊。

分類:

  1. 普通Pod: 一旦被建立,就會放入到etcd中儲存, 隨後被master排程到某個具體的Node上並進行繫結(Binding),隨後被Node的kubelet程序例項化成Docker容器啟動。
  2. 靜態Pod(Static Pod): 存放在某個具體的Node上的一個具體檔案內,並且只在此Node上啟動執行。

預設情況Pod裡某個容器停止,k8s會自動檢測到並重啟這個Pod(重啟Pod內所有容器),如果Pod所在Node宕機,將會將Node上所有Pod重新排程到其他節點上。

Endpoint: Pod的IP加上容器的埠(containerPort)

Pod Volume: 定義在Pod上, 被各個容器掛載到自己的檔案系統中。

檢視pod描述資訊,定位問題。

kubectl describe pod <pod name>

Event:是一個事件的記錄, 記錄了時間的最早產生時間、最後重現時間、重複次數、發起者、型別,以及導致此時間的原因等眾多資訊。Event 通常會關聯到某個具體的資源物件上,是排查故障的重要參考資訊。

Pod 對伺服器上計算資源設定限額

  1. CPU : CPU的資源單位為CPU(Core) 的數量,是一個絕對值。
  2. Memory: 單位是記憶體位元組數,也是一個絕對值

k8s裡通常以千分之一的CPU配額為最小單位。用m來表示。通常一個容器的配額被定義為100~300m,既0.1~0.3個cpu.因為是一個絕對值,所以無論是一個Core還是48個Core的機器 100m所代表的使用量是一樣的。

k8s裡一個計算資源進行配額限定需要設定兩個引數

  1. Requests: 該資源的最小申請量,系統必須滿足要求。
  2. Limits 該資源最大循序使用的量,不能被突破,當容器試圖使用超過這個量的資源時,可能會被k8s kill並重啟。

通常將 Request 設定為一個比較小的值,符合容器平時的工作負載情況下的資源需求,把Limits設定為峰值負載下資源佔用的最大值。。

如表明mysql容器最少申請0.25個CPU和64Mib記憶體,在執行時,mysql鎖能使用的資源配額為 0.5個CPU及128Mib記憶體

spec:
  containers:
  - name: db
    image: mysql
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"
                

Label 標籤

Label 是一個鍵值對,可以附加到各種資源物件上,如 Node、Pod、Service、RC等。

一個資源可以定義任意數量的Lable, 同一個Lable也可以被新增到任意數量的資源物件上去。

可以在物件定義時確定,也可以在物件建立後動態新增或者刪除。

通過制定的資源物件捆綁一個或多個不同的Label 來實現多維度的資源分組管理,方便的進行資源分配、排程、配置、部署等管理工作。

常用標籤示例

  • 版本標籤: "release": "stable", "release": "canary" ...
  • 環境標籤: "environment": "dev", "environment": "qa", "environment": "production",
  • 架構標籤: "tier": "frontend", "tier": "backend", "tier": "middleware",
  • 分割槽標籤: "partition": "customerA",
  • 質量管控標籤: "track": "daily", "track": "weekly",

Label Selector 標籤選擇器

通過標籤選擇器(Label Selector) 查詢和篩選擁有Label的資源物件。

Label Selector 表示式:

  • 基於等式(Equality-based):
    • name = redis 匹配所有具有標籤的資源物件
    • name != mysql 匹配不具有標籤的物件
  • 基於集合(Set-based):
    • name in (redis, mysql) 匹配所有具有標籤 name=redis 或 name=mysql的資源物件
    • name not in (redis) 匹配所有不具有標籤 name=redis的資源物件

可以使用多個Label Selector 表示式組合實現複雜的條件選擇,多個表示式使用,進行分隔,幾個條件是AND關係

name=redis,env!=production    

新出現的管理物件Deployment、ReplicaSet、DaemonSet和Job 可以使用Selector中使用基於集合篩選條件定義

selector:
  matchLabels:
    app: myweb
  matchExpressions:
    - {key: tier, operator: In, values: [frontend]}
    - {key: environment, operator: NotIn, values: [dev]}  
  • matchLabels: 定義一組Label, 與直接寫在Selector作用相同
  • matchExpressions: 定義一組篩選條件,可用條件運算子包括: In、NotIn、Exists和DoesNotExist。

同時設定了這兩組,他們的關係是 AND 關係,所有條件都滿足才能完成篩選。

Replication Controller

RC: 宣告某種Pod的副本數量在任意時刻都符合某種預期值

  • Pod 期待的副本數(replicas)
  • 用於篩選目標Pod的Label Selector
  • 當Pod的副本數量小於預期數量時,用於建立新Pod的模版(template)

定義RC提交到k8s集群后,master節點的Controller Manager元件獲得通知,定期巡檢系統中存活的目標Pod, 並確保Pod例項的數量剛好等於此RC的期望值。 如果過多的Pod執行,就停一些Pod,否則會建立一些Pod.

通過RC實現了使用者應用叢集的高可用,減少手工運維工作。

在執行時,可以通過修改RC的副本數量,來實現Pod的動態縮放(Scaling)。

kubectl scale rc redis-slave --replicas=3

注意 刪除RC並不會影響通過該RC已建立好的Pod, 為了刪除所有Pod,可以將replicas的值為0,然後更新該RC.

還提供了 stop 和 delete 命令來一次性刪除RC和RC 控制的所有Pod.

通過RC可以實現 滾動升級(Rolling Update)

Kubernetes v1.2時,升級為新的概念 Replica Set, 下一代RC.

區別:

  • Replica Sets 支援基於集合的Label selector
  • RC 只支援基於等式的Label selector
apiVersion: v1
kind: ReplicaSet # 對比: 這裡寫的是 ReplicationController
metadata:
  name: mysql 
spec:
  selector: 
      matchLabels:
        app: myweb
      matchExpressions:
        - {key: tier, operator: In, values: [frontend]}

當前我們很少單獨使用,主要被Deployment這個高層物件所使用。我們在使用Deployment時,無須關心如何建立ReplicaSet.

  • 改變RC 副本數量,可以實現Pod的擴容和縮容的功能
  • 改變RC 裡Pod 模版的映象版本, 可以實現Pod的滾動升級功能。

Deployment

為了更好解決Pod編排問題,內部使員工ReplicaSet

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deploy
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
      release: dev
  template:
    metadata:
      labels:
        app: myapp
        release: dev
    spec:
      containers:
      - name: myapp-containers
        image: ikubernetes/myapp:v1
        ports:
        - name: http
          containerPort: 80

建立:

kubectl create -f deployment.yaml

檢視Deployment的資訊

➜  k8s kubectl get deployments
NAME           DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
myapp-deploy   1         1         1            1           1m
  • DESIRED: Pod副本數量的期望值, 既Deployment裡定義的Replica
  • CURRENT: 當前Replica的值,這個值不斷增加,直到達到DESIRED為止, 完成整個部署過程
  • UP-TO-DATE: 最新版本的Pod的副本數量,用於指示在滾動升級的過程中,有多少Pod副本已成功升級
  • AVAILABLE: 當前叢集可用Pod副本數量, 既叢集中當前存活的Pod數量。

檢視對應的ReplicaSet, 命名和Deployment有關

➜  k8s kubectl get rs
NAME                     DESIRED   CURRENT   READY     AGE
myapp-deploy-f4bcc4799   1         1         1         10m

檢視Pod, 以ReplicaSet的名稱為字首, 清晰表明那些rs建立了哪些Pod,對於滾動升級,可以容易排除錯誤。

➜  k8s kubectl get pods
NAME                           READY     STATUS    RESTARTS   AGE
myapp-deploy-f4bcc4799-d9pqn   1/1       Running   0          14m

Horizontal Pod Autoscaler

Pod 橫向自動擴容, 簡稱HPA

HPA有兩種方式作為Pod負載的度量指標

  • CPUUtilizationPercentage
  • 應用程式自定義的度量指標,比如服務在每秒內的相應的請求數(TPS和QPS)

CPUUtilizationPercentage 是一個算數平均值,既目標Pod所有副本自身的CPU利用率的平均值。

一個Pod自身CPU利用率是該Pod當前CPU的使用量除以它的Pod Request的值。

如:一個Pod的PodRequest為0.4,當前CPU使用率是0.2, 那麼它CPU使用率為50% (0.2/0.4=0.5)

這樣我們就可以算出一個RC控制的Pod副本的CPU利用率的算數平均值。

如果某個時刻CPUUtilizationPercentage的值超過80%,則意味著當前的Pod副本數量可能不足以支撐接下來更多的請求,需要動態擴容。 當峰值時段過去,CPU利用率又降下來,此時對應的Pod副本應該自動減少到一個合理水平。

CPUUtilizationPercentage計算使用到的Pod的CPU使用量通常在1min內的平均值,目前通過Heapster擴充套件元件來得到這個值。所以需要安裝Heapster.

如果目標沒定義Pod Request,則無法使用CPUUtilizationPercentage

StatefulSet

提供有狀態的服務。

  • StatefulSet 裡的每個Pod都有穩定、唯一的網路標識,可以用來發現叢集內的其他成員。如 StatefulSet 的名字是kafka, 第一個pod叫kafka-0, 依次類推
  • StatefulSet 控制的Pod副本的啟停順序是受控的,操作第n個Pod時, 前n-1個Pod已經執行且準備好的狀態。
  • StatefulSet 裡的Pod採用穩定的持久化儲存卷,通過PV/PVC來實現, 刪除Pod時預設不會刪除與StatefulSet相關的儲存卷。

StatefulSet除了要與PV卷捆綁使用以儲存Pod的狀態資料,還要與Headless Service配合,每個定義中要宣告它屬於哪個Headless Service。

Headless Service 與普通Service的區別在於,它沒有Cluster IP, 如解析Headless Service的DNS域名, 則返回的是該Service對應的全部Pod的Endpoint列表。

StatefulSet在Headless Service的基礎上又為控制的每個Pod例項建立了一個DNS域名:

$(podname).$(headless service name)

如: 3 個節點的kafka, Headless Service名字kafka,則3個Pod的DNS名稱分別為kafka-0.kafka、kafka-1.kafka、kafka-2.kafka

這些DNS名稱可以直接在叢集的配置檔案中固定下來。

Service(服務)

每個Service相當於微服務架構中的 "微服務"

Service與其後端Pod副本叢集通過Label Selector 來實現"無縫對接"

RC 保證 Service 的服務能力和服務質量始終處於預期的標準值。

執行在Node上的kube-proxy程序負責負載,把請求轉發到後盾Pod例項上, 內部實現負載與會話保持。

Cluster IP : Service不是共用一個負載均衡器的IP地址,而是沒個Service分配了一個全域性唯一的虛擬IP地址, 這個IP叫Cluster IP

這樣每個服務都變成了具有唯一IP地址的"通訊節點",服務變成了基礎的TCP網路通訊問題。

Pod的Endpoint地址會隨著Pod的銷燬和重新建立而發生改變,因為新Pod的IP地址和舊的Pod的不同

Service一旦被建立,Kubernetes就會自動為它分配一個可用的Cluster IP, 而且在Service的整個生命週期內, 它的Cluster IP不會發生改變。

所以服務發現使用Service的NameCluster IP地址做一個DNS域名對映就解決問題。

建立一個Service: tomcat-service.yaml

apiVersion: v1
kind: Service 
metadata:
  name: tomcat-service
spec:
  ports:
  - port: 8080
  selector:
    tier: frontend  

建立

kubectl create -f tomcat-service.yaml

這時候就會去對應一個Pod, 使用下面的命令檢視對應情況

kubectl get endpoints

檢視Cluster IP

kubectl get svc tomcat-service -o yaml

服務多埠問題,存在多個Endpoint,定義例子如:

apiVersion: v1
kind: Service 
metadata:
  name: tomcat-service
spec:
  ports:
  - port: 8080
   name: service-port
  - port: 8005
     name: shutdown-port 
  selector:
    tier: frontend  

服務發現機制

Service 都有一個唯一的Cluster IP 及唯一的名字。名字由開發者自己定義,部署也不需要改,所以完全可以固定在配置中。

最早使用環境變數(env),在每個Pod的容器在啟動時,自動注入。但是不夠直觀。

通過Add-On增值包的方式引入了DNS系統, 把服務名作為DNS域名, 這樣程式就可以直接使用服務名來簡歷通訊連線了。

外部訪問Service的問題

三種IP

  • Node IP: Node節點的IP地址
  • Pod IP: Pod的IP的地址
  • Cluster IP: Service的IP地址
Node IP

Node IP是 k8s叢集中沒個節點的物理網絡卡的IP地址, 這是一個真實存在的物理網路。

這表明k8s叢集之外的節點訪問k8s叢集某個節點或TCP/IP服務,必須通過Node IP 通訊。

Pod IP

Pod IP 是每個Pod的IP地址,它是根據Docker Engine 根據 docker0 網橋IP地址段進行分配的,通常是一個虛擬的二層網路。

所以k8s裡一個Pod裡的容器訪問另一個Pod裡的容器,就通過Pod IP 所在的虛擬二層網路進行通訊,真實流量則是通過Node IP所在的物理網絡卡流出。

Cluster IP

Cluster IP 也是虛擬IP,

  • Cluster IP 只作用於 Kubernetes Service 這個物件,並由k8s管理和分配IP地址 (來源於 Cluster IP 地址池)
  • 無法被Ping, 沒有一個"實體網路物件"來響應
  • 只能結合Service Port 組成一個具體的通訊埠,單獨的Cluster IP 不具備TCP/IP通訊的基礎,並且他們屬於叢集內部封閉空間,如叢集外想訪問,需要額外的工作。
  • k8s 叢集內 Node IP網、Pod IP網與 Cluster IP網之間通訊,採用k8s自己設計的一套特殊路由規則,與我們熟悉的IP路由有很大不同。

Cluster IP 屬於 k8s 內部的地址,無法在叢集外部直接使用這個地址。

採用NodePort 解決上述問題

apiVersion: v1
kind: Service 
metadata:
  name: tomcat-service
spec:
  type: NodePort
  ports:
  - port: 8080
    nodePort: 31002  # 手動指定NodePort 埠號,不然會自動分配。
  selector:
    tier: frontend  

NodePort還沒完全解決外部訪問Service的所有問題,如負載均衡。最好使用一個負載均衡器,由負載均衡器負責轉發流量到後面某個Node的NodePort.

如: 使用硬體 Load balancer 負載, 活 HAProxy 或者 Nginx.

谷歌GCE公有云上,將 type=NodePort 改為 type=LoadBalancer, k8s會自動建立一個對應的Load balancer 使用。其他公有云實現此驅動,也可使用。

Volume (儲存卷)

Volume 是 Pod 中能夠被多個容器訪問的共享目錄。

k8s中的 Volume 定義在Pod上, 然後被一個Pod裡的多個容器掛載到具體的檔案目錄下。

k8s中的 Volume 與Pod的生命週期相同, 與容器的生命週期不相關。

當容器終止或者重啟時,Volume 中的資料不會丟失。

k8s 支援多種檔案型別的 Volume.

使用: 在Pod上宣告一個 Volume, 然後在容器裡引用Volume並Mount到容器的某個目錄上。

如: 給 Pod 增加一個 名字為 datavol 的 Volume, 掛載到 /mydata-data上


template:     
metadata:
  labels:
    app: mysql  
spec:
  volumes: 
    - name: datavol
      emptyDir: {}
  containers:    
  - name: mysql   
    image: mysql  
    volumeMounts:
      - mountPath: /mydata-data
        name: datavol

emptyDir

一個emptyDir Volume 是在Pod 分配到Node時建立的。它的內容為空,並且無須指定宿主機上對應的檔案目錄。這是k8s自動分配的一個目錄。 Pod 從Node上移除, emptyDir 中的資料也會被永久刪除。

用途:

  • 臨時空間, 例如用於某些應用程式執行時所需的零時目錄,且無須永久儲存。
  • 長時間任務的中間過程Check Point的零時儲存目錄
  • 一個容器需要從另一個容器中獲取資料的目錄(多容器共享目錄)

hostPath

hostPath 為在Pod上掛載宿主機上的檔案或目錄,

  • 容器應用程式生成的日誌檔案需要永久儲存時,可以使用宿主機的高速檔案系統進行儲存。
  • 需要訪問宿主機Docker 引擎內部資料結構的容器應用時, 可以通過定義hostPath為宿主機/var/lib/docker目錄,使容器內部可以直接訪問Docker的檔案系統。

使用注意:

  • 在不同的Node 上具有相同配置的Pod 可能會因為宿主機上的目錄和檔案不同而導致對Volume上的目錄和檔案訪問結果不一致。
  • 如果使用了資源配額管理,則k8s無法將hostPath在宿主機上使用資源納入管理。
volumes: 
- name: datavol
  hostPath:
    path: "/data"

gcePersistentDisk (用不到)

使用這種型別的Volume 表示使用谷歌公開雲提供的永久磁碟(Persisteent Disk, PD)存放Volume的資料,它與emptyDir不同,會永久儲存。 當Pod被刪除時,PD只會解除安裝,但不會被刪除。你需要先建立一個永久磁碟(PD), 才能使用

gcloud compute disks create --size=500GB --zone=us-centrall-a my-data-disk
volumes: 
- name: datavol
  gcePersistentDisk:
    pdName: my-data-disk
    fsType: ext4

awsElasticBlockStore (用不到)

亞馬遜公有云提供的EBS Volume儲存資料,需要先建立一個ESB Volume才能使用。

一些限制:

  • Node(執行kubelet的節點) 需要是 AWS EC2例項
  • 這些AWS EC2 例項需要與 EBS volume存在相同的 region 和 availability-zone中,
  • EBS 只支援當個EC2 例項 mount 一個 volume
aws ec2 create-volume --availability-zone eu-west-1a --size 10 --volume-type gp2
volumes: 
- name: datavol
  awsElasticBlockStore:
    volumeID: aws://<availability-zone>/<volume-id>
    fsType: ext4

NFS (用不到)

使用NFS網路檔案系統提供的共享目錄儲存資料時,需要在系統部署一個NFS Server.

volumes: 
- name: nfs
  nfs:
    server: nfs-server.localhost
    path: "/"

其他 (用不到)

  • iscsi: 使用iSCSI儲存裝置上的目錄掛載到Pod中
  • flocker: 使用Flocker來管理儲存卷
  • glusterfs: 使用 GlusterFS 網路檔案系統的目錄
  • rbd: 使用Ceph塊裝置共享儲存(Rados Block Device)
  • gitRepo: 掛載一個空目錄,並從git庫clone一個git repository
  • secret: 一個secret volume 用於為Pod 提供加密資訊,可以將定義在k8s中的secret 直接掛載為檔案讓Pod訪問。secret volume 是通過tmfs(記憶體檔案系統實現的,所以這種型別的volume總是不會持久化)

Persistent Volume

之前說的Volume是定義在Pod上,屬於"計算資源"的一部分

"網路儲存" 是相對獨立於"計算資源"而存在的一種實體資源

Persistent Volume: 簡稱 PV 。

Persistent Volume Claim (簡稱PVC) 。

可以認為是叢集中某個網路儲存對應的一塊儲存,與 Volume類似

區別:

  • PV 只能是網路儲存, 不屬於Node, 但可以在每個Node 上訪問。
  • PV 並不是定義在Pod上的,而是獨立於Pod之外定義。

例子: NFS型別的PV的yaml, 宣告需要5Gi的空間

apiVersion: v1
kind: PersistentVolume 
metadata:
  name: pv0003
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  nfs: 
    path: /somepath
    server: 127.17.0.2     

PV 的 accessModes 屬性

  • ReadWriteOnce: 讀寫許可權、並且只能被單個Node掛載
  • ReadOnlyMany: 只讀許可權、允許多個Node掛載
  • ReadWriteMany: 讀寫許可權、允許多個Node掛載

如果Pod 想申請PV, 需要先定義一個PVC.

apiVersion: v1
kind: PersistentVolumeClain 
metadata:
  name: myclaim
spec:
  accessModes:
    - ReadWriteOnce
  resources: 
    requests:
      storage: 8Gi

然後在Pod 的 Volume 定義上引用上述PVC :

volumes: 
- name: datavol
  persistentVolumeClain:
    claimName: myclaim

Namespace (名稱空間)

namespace 在很多情況下用於多租戶資源隔離。通過將叢集內部的資源物件分配到不同的namespace 形成邏輯上分組的不同專案、小組、使用者組。 便於不同分組在共享使用整個叢集的資源的同時還能被分別管理。

k8s 啟動後,會建立一個名為default的Namespace 通過

kubectl get namespaces

如果不特別指明,則使用者建立的Pod、RC、Service都將被系統建立到這個預設namespace。

建立一個名為 development 的 Namespace:

apiVersion: v1
kind: Namespace 
metadata:
  name: development

建立後可以指定這個資源物件屬於哪個Namespace.

定義一個名為busybox的Pod, 放入上面建立的:

apiVersion: v1
kind: Pod 
metadata:
  name: busybox
  namespace: development
spec:
    ...  

這時使用命令將看不到上面建立的pod, 預設使用的是default

kubectl get pods

需要新增引數--namespace 來檢視

kubectl get pods --namespace=development

Annotation 註釋

使用key/value 鍵值對

Annotation 用來記錄的資訊如下:

  • build資訊、release資訊、docker映象訊息等,如時間戳、release id 號、 PR號、
  • 日誌庫、監控庫、分析庫、等資源庫的地址資訊。
  • 程式除錯工具,如工具名稱、版本號、
  • 團隊的聯絡資訊,例如:電話號、負責人名稱