程式碼研究室簡介
1. 總覽
Artifact Registry 是完全受管理的套件管理工具,可提供統一工具來管理 OCI 容器映像檔和語言套件 (例如 Maven 和 npm)。
Artifact Registry 與 Google Cloud 的多項其他服務完全整合,例如以下範例:
- Cloud Build 可以直接將映像檔構件上傳至 Artifact Registry。
- Cloud Deploy 可直接將 Artifact Registry 映像檔部署至各種執行階段環境。
- 它會為 Cloud Run 和 GKE 等容器執行階段提供映像檔,並啟用進階效能最佳化功能,例如圖片串流。
- Artifact Registry 可做為 Artifact Analysis 的偵測點,持續監控已知的安全漏洞。
- Cloud IAM 可讓您以一致且精細的方式控管構件存取權和權限。
本實驗室將以實作教學課程的形式,逐步介紹這些功能。
學習目標
本實驗室的學習目標為何?
- 為容器和語言套件建立不同的存放區
- 使用 Artifact Registry 建立及使用容器映像檔
- 使用 Artifact Registry 分析構件的安全性和內容
- 設定及使用 Artifact Registry 的 Java Maven 依附元件
2. 設定和需求
自學環境設定
- 登入 Google Cloud 控制台,然後建立新專案或重複使用現有專案。如果您還沒有 Gmail 或 Google Workspace 帳戶,請務必建立帳戶。
- 「Project name」是這個專案參與者的顯示名稱。這是 Google API 不會使用的字元字串。您隨時可以更新。
- 專案 ID 在所有 Google Cloud 專案中都是不重複的值,且無法變更 (設定後即無法變更)。Cloud 控制台會自動產生專屬字串,您通常不需要理會這個字串。在大多數程式碼研究室中,您都需要參照專案 ID (通常會以
PROJECT_ID
表示)。如果您不喜歡系統產生的 ID,可以產生另一個隨機 ID。或者,您也可以自行嘗試,看看是否可用。在這個步驟完成後就無法變更,且會在整個專案期間維持不變。 - 提醒您,有些 API 會使用第三個值「專案編號」。如要進一步瞭解這三個值,請參閱說明文件。
- 接下來,您需要在 Cloud 控制台中啟用帳單功能,才能使用 Cloud 資源/API。執行這個程式碼研究室不會產生太多費用,甚至可能完全不會產生費用。如要關閉資源,避免在本教學課程結束後繼續產生費用,您可以刪除建立的資源或專案。Google Cloud 新使用者可享有價值 $300 美元的免費試用期。
設定 gcloud
在 Cloud Shell 設定專案 ID 和專案編號,分別儲存為 PROJECT_ID
和 PROJECT_NUMBER
變數。
export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
啟用 Google 服務
gcloud services enable \
cloudresourcemanager.googleapis.com \
run.googleapis.com \
artifactregistry.googleapis.com \
containerregistry.googleapis.com \
containerscanning.googleapis.com \
binaryauthorization.googleapis.com \
cloudbuild.googleapis.com
取得原始碼
本實驗室的原始碼位於 GitHub 的 GoogleCloudPlatform 組織中。請使用下列指令複製該項目。
git clone https://github.com/GoogleCloudPlatform/java-docs-samples
3. 推送容器映像檔
在 Artifact Registry 中建立 Docker 存放區
如先前所述,Artifact Registry 支援各種存放區格式,可讓您管理容器映像檔和語言套件。與不同類型構件存放區的互動方式已在規格中定義,並且是廣泛採用的標準。舉例來說,Maven 依附元件的請求與 Node 依附元件的請求不同。
為了支援特定的構件 API 規格,Artifact Registry 需要在對應的存放區類型中管理您的構件。建立新存放區時,請傳入 --repository-format
標記,以表示存放區類型。
如要建立 Docker 映像檔的第一個存放區,請在 Cloud Shell 中執行下列指令:
gcloud artifacts repositories create container-example --repository-format=docker \
--location=us-central1 --description="Example Docker repository"
如果出現 Cloud Shell 授權提示,請按一下「授權」
前往 Google Cloud 控制台 - Artifact Registry - 存放區,並注意新建立的 Docker 存放區名為 container-example
,如果您按一下,會發現目前是空的
設定 Docker 驗證以存取 Artifact Registry
連線至 Artifact Registry 時,必須提供憑證才能存取資料。您可以設定 Docker 以順暢地使用 gcloud 憑證,而無需設定個別憑證。
在 Cloud Shell 中執行下列指令,將 Docker 設為使用 Google Cloud CLI,驗證 us-central1
區域中的 Artifact Registry 要求。
gcloud auth configure-docker us-central1-docker.pkg.dev
如果指令提示您確認是否要變更 Cloud Shell Docker 設定,請按下 Enter 鍵。
探索範例應用程式
在先前步驟中複製的 Git 存放區中,會提供範例應用程式。切換至 Java 目錄並查看應用程式程式碼。
cd java-docs-samples/run/helloworld/
ls
這個資料夾包含可轉譯簡單網頁的 Java 應用程式範例:除了與本研究室無關的各種檔案外,這個資料夾還包含 src
資料夾下的原始碼,以及我們用來建構容器映像檔的 Dockerfile。
建構容器映像檔
您必須先建立容器映像檔,才能將其儲存至 Artifact Registry。
執行下列指令來建構容器映像檔,並使用完整的構件登錄機制路徑標記映像檔:
docker build -t us-central1-docker.pkg.dev/$PROJECT_ID/container-example/java-hello-world:tag1 .
將容器映像檔推送至 Artifact Registry
執行下列指令,將容器映像檔推送至先前建立的存放區:
docker push us-central1-docker.pkg.dev/$PROJECT_ID/container-example/java-hello-world:tag1
在 Artifact Registry 中查看映像檔
前往 Google Cloud 控制台 - Artifact Registry - 存放區.
開啟 container-example
存放區,確認 java-hello-world
映像檔是否存在。
按一下圖片,並注意標示為 tag1
的圖片。由於我們已透過 containerscanning.googleapis.com
服務啟用自動掃描圖片功能,因此您會看到「安全漏洞掃描」正在執行或已完成。完成後,您可以查看系統偵測到此圖像修訂版本的安全漏洞數量。我們將在下一節探討安全漏洞和其他構件洞察資料。
4. 檢查容器映像檔
您已將第一張圖片推送至 container-example
存放區,現在我們可以進一步查看這張圖片。在「版本」分頁中,按一下我們剛才建立的版本。如要顯示圖片的更多細節,請按照下列步驟操作:
上方的複製按鈕特別實用,因為它提供簡單的方法,可存取該圖片版本的完整合格圖片 URI,包括 SHA 雜湊值。這個 URI 可用於擷取特定映像檔版本,或做為 Kubernetes 部署或 Cloud Run 服務中的映像檔參照。如要測試圖片 URI,您可以在 Cloud Shell 中執行下列指令:
docker pull $IMAGE_URI
瞭解依附元件
前往頂端的「Dependencies」(依附元件) 分頁,即可查看在圖片中偵測到的所有依附元件。請注意,這份清單會列出語言依附元件和作業系統層級的依附元件。您也可以查看與各依附元件相關聯的軟體授權。
仔細觀察後,您會發現系統尚未填入 SBOM 資訊。如要為構件填入 SOM,您可以在 Cloud Shell 中使用完整的映像檔 URI (可從頂端麵包屑列複製) 執行下列指令。
gcloud artifacts sbom export --uri $IMAGE_URI
重新整理頁面後,頁面上會顯示自動產生的 SBOM 連結,該 SBOM 已儲存在 Cloud Storage 中。如果您需要為映像檔產生 SBOM,建議您自動為構件產生 SBOM,並將產生作業納入 CI/CD 管道。
探索映像檔安全漏洞
按一下檢視畫面頂端的「安全漏洞」分頁標籤,即可查看在映像檔中偵測到的所有安全漏洞。除了頂端的漏洞摘要,您還可以在底部的表格中查看完整的漏洞清單。每個資料列都會連結至 CVE 公告,指出嚴重程度和來源套件。對於有修正程式可用的安全漏洞,我們也會提供如何更新依附元件以修正安全漏洞的操作說明。
5. 虛擬和遠端存放區
在上一節中,我們使用單一圖片存放區來推送及拉取圖片。這項做法非常適合小規模的用途,但對於大型組織來說,尤其是有不同團隊需要對其存放區擁有自主權的大型組織,則會遇到挑戰。團隊或業務單位通常會擁有自己的圖片存放區,並設定相應的權限和設定。為簡化這些存放區中的映像檔使用方式,並讓使用者不必瞭解底層的組織結構,Artifact Registry 提供虛擬存放區,可匯集來自多個底層存放區的資源。潛在架構可能如下所示:
Docker Hub 的遠端存放區
Docker Hub 是熱門的公開映像檔登錄,可代管許多開放原始碼容器映像檔。雖然直接使用公開存放區很簡單,但在實際工作環境中會遇到許多挑戰,我們可以透過 Artifact Registry 中的遠端存放區克服這些挑戰。
遠端存放區可讓您將要求代理至上游註冊中心,並在過程中快取圖片。這麼做不僅可縮短圖片的下載時間,還能避免依賴外部服務的正常運作時間,並讓您套用與自有圖片相同的安全性和存取權政策。
如要為 Docker Hub 建立遠端存放區,您可以在 Cloud Shell 中執行下列指令:
gcloud artifacts repositories create dockerhub \
--repository-format=docker \
--mode=remote-repository \
--remote-docker-repo=docker-hub \
--location=us-central1 \
--description="Example Remote Repo for Docker Hub"
您現在應該會在 Artifact Registry 存放區清單中看到其他存放區:
如要測試遠端存放區是否能將要求轉送至遠端存放區,請在 Cloud Shell 中執行下列指令,提取 nginx 映像檔:
docker pull us-central1-docker.pkg.dev/$PROJECT_ID/dockerhub/nginx:stable-alpine
拉取成功後,您也可以在 Cloud 控制台中查看存放區,並瞭解快取的 nginx 映像檔現在提供與您自行建構的映像檔相同的依附元件和安全漏洞報表。
建立虛擬存放區
只要按照我們目前採用的程序操作,您就能為每個團隊或業務建立多個存放區,並明確定義各個存放區的擁有權和 IAM 權限。我們也可以為遠端存放區建立 Proxy,讓您更輕鬆安全地使用第三方圖片。如果您將觀點轉移至這些圖片的使用者,就會發現大量存放區的缺點。開發人員該如何判斷在部署作業中應使用哪個映像檔存放區?
如要簡化使用方式,並隱藏基礎層的存放區,您可以在 Cloud Shell 中使用下列指令,在 Artifact Registry 中建立虛擬存放區:
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member serviceAccount:service-$PROJECT_NUMBER@gcp-sa-artifactregistry.iam.gserviceaccount.com \
--role roles/artifactregistry.reader
cat <<EOF > /tmp/upstream.json
[{
"id" : "hello-repo",
"repository" : "projects/$PROJECT_ID/locations/us-central1/repositories/container-example",
"priority" : 100
},{
"id" : "dockerhub",
"repository" : "projects/$PROJECT_ID/locations/us-central1/repositories/dockerhub",
"priority" : 101
}]
EOF
gcloud artifacts repositories create all-images \
--repository-format=docker \
--mode=virtual-repository \
--location=us-central1 \
--upstream-policy-file=/tmp/upstream.json \
--description="Example Virtual Repo"
我們現在可以從虛擬存放區提取映像檔,而不會洩漏底層結構。如要確認一切運作正常,您可以在 Cloud Shell 中執行下列指令:
docker pull us-central1-docker.pkg.dev/$PROJECT_ID/all-images/java-hello-world:tag1
docker pull us-central1-docker.pkg.dev/$PROJECT_ID/all-images/nginx:stable-alpine
6. 部署至 Cloud Run
有了各個存放區和圖片,我們現在可以將這些項目用於部署作業。為了說明實際用途,並避免部署額外的基礎架構,我們會將容器部署至 Cloud Run。最簡單的部署方式,就是在 Cloud Shell 中執行下列指令:
gcloud run deploy hello-world \
--image us-central1-docker.pkg.dev/$PROJECT_ID/all-images/java-hello-world:tag1 \
--region us-central1 \
--allow-unauthenticated
部署完成後,系統會顯示自動產生的網址,您可以透過這個網址存取服務。
Deploying container to Cloud Run service [hello-world] in project [my-project] region [us-central1] OK Deploying... Done. OK Creating Revision... OK Routing traffic... OK Setting IAM Policy... Done. Service [hello-world] revision [hello-world-00001-wtc] has been deployed and is serving 100 percent of traffic. Service URL: https://hello-world-13746229022.us-central1.run.app
如果您在新瀏覽器分頁中開啟該網址,應該會看到成功的「Hello World」訊息。
7. 強化供應鏈安全性
容器映像檔已部署至實際環境,現在是時候看看如何強化端對端供應鏈了。在上一節中,我們探討了 Artifact Registry 的容器分析如何提供有關映像檔中所用程式庫和授權的深入分析資訊。不過,惡意人士仍有可能透過供應鏈將有害內容加入您的圖片。在本節中,我們將探討如何使用 SLSA 架構為建構構件引入認證,甚至利用構件本身的密碼編譯簽章,確保只有可信任的構件才能部署至 Cloud Run 執行階段。
使用 Cloud Build 進行 SLSA 認證
SLSA 架構可為供應鏈構件提供不同層級的證據。規格和實作方式乍看之下可能很複雜,但使用 Cloud Build 建立 SLSA 認證的操作方式,就跟新增 cloudbuild.yaml
規格一樣簡單,只要將 requestedVerifyOption
設為 VERIFIED
即可。
針對我們的應用程式,我們可以在 Cloud Shell 中執行下列指令,在 helloworld 資料夾中建立 cloudbuild.yaml
檔案。
cat <<EOF > cloudbuild.yaml
steps:
- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', '\$_IMAGE_URI', '.']
- name: 'gcr.io/cloud-builders/docker'
args: ['push', '\$_IMAGE_URI']
images:
- '\$_IMAGE_URI'
options:
requestedVerifyOption: VERIFIED
substitutions:
_IMAGE_URI: us-central1-docker.pkg.dev/$PROJECT_ID/container-example/java-hello-world:latest
EOF
接下來,我們會在 Cloud Shell 中執行下列指令,建立新的 Cloud Build 工作,以便建構新版的 Java Hello World 映像檔。
gcloud builds submit --substitutions=_IMAGE_URI=us-central1-docker.pkg.dev/$PROJECT_ID/container-example/java-hello-world:cloud-build
建構作業完成後,我們可以前往 Google Cloud 控制台的 Cloud Build UI,開啟建構作業並查看「Build Summary」(建構摘要) 底下的「Build Artifacts」(建構構件),瞭解我們達成的 SLSA 等級。圖片中顯示的按鈕可用於查看「安全性深入分析」。點選後,您會看到 SLSA 認證,以及我們先前在 Artifact Registry UI 中推送本機建構時,所見的熟悉漏洞報告。
您也可以在 Cloud Shell 中執行下列指令,擷取映像檔的 SLSA 來源:
gcloud artifacts docker images describe \
"us-central1-docker.pkg.dev/$PROJECT_ID/container-example/java-hello-world:cloud-build" \
--show-provenance
使用二進位授權要求 Cloud Build 來源
有了 Cloud Build 管道,您就能確保所有要部署至正式版的映像檔,都是使用可編寫程式碼且可重現的建構環境建構而成,這不是很棒嗎?
這時就需要使用二進位授權功能。您可以在容器執行階段前方放置閘道器,以便檢查容器映像檔,並驗證是否存在可信任的認證。如果找不到認證,系統會根據設定,建立稽核記錄項目或完全封鎖部署作業。
如要變更專案的預設二進位授權設定,以便要求 Cloud Run 核發的內建認證,請在 Cloud Shell 中執行下列指令:
cat << EOF > /tmp/policy.yaml
defaultAdmissionRule:
enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
evaluationMode: REQUIRE_ATTESTATION
requireAttestationsBy:
- projects/$PROJECT_ID/attestors/built-by-cloud-build
name: projects/$PROJECT_ID/policy
EOF
gcloud container binauthz policy import /tmp/policy.yaml
您當然也可以新增自訂的 Attestor,但這不在本程式碼研究室的範圍內,因此我們將其列為選修的課外作業。
如要在 Cloud Run 服務上強制執行二進位授權,請在 Cloud Shell 中執行下列指令:
gcloud run services update hello-world \
--region us-central1 \
--binary-authorization=default
我們先重新部署本機建構的映像檔,測試二進位授權是否正確套用
gcloud run deploy hello-world \
--image us-central1-docker.pkg.dev/$PROJECT_ID/all-images/java-hello-world:tag1 \
--region us-central1
如預期,您應該會收到錯誤訊息,說明為何無法部署圖片,訊息如下所示:
Image us-central1-docker.pkg.dev/my-project/all-images/java-hello-world@sha256:71eebbf04bf7d1d023e5de5e18f786ea3b8b6411bf64c8def3301c71baca0518 denied by attestor projects/my-project/attestors/built-by-cloud-build: No attestations found that were valid and signed by a key trusted by the attestor
因此,如要將新版本部署至 Cloud Run 服務,我們必須提供使用 Cloud Build 建構的映像檔。
gcloud run deploy hello-world \
--image us-central1-docker.pkg.dev/$PROJECT_ID/all-images/java-hello-world:cloud-build \
--region us-central1
這次的部署作業應該會成功,並顯示類似以下的部署成功訊息:
Deploying container to Cloud Run service [hello-world] in project [my-project] region [us-central1] OK Deploying... Done. OK Creating Revision... OK Routing traffic... Done. Service [hello-world] revision [hello-world-00005-mq4] has been deployed and is serving 100 percent of traffic. Service URL: https://hello-world-13746229022.us-central1.run.app
8. 管理 Java Maven 語言套件
在本節中,您將瞭解如何設定 Artifact Registry Java 存放區,並上傳套件至其中,以便在不同應用程式中加以利用。
建立 Maven 套件存放區
在 Cloud Shell 中執行下列指令,建立 Java 構件存放區:
gcloud artifacts repositories create java-repo \
--repository-format=maven \
--location=us-central1 \
--description="Example Java Maven Repo"
如果出現 Cloud Shell 授權提示,請按一下「授權」
前往 Google Cloud 控制台 - Artifact Registry - Repositories,然後查看您新建的 Maven 存放區 (名為 java-repo
)。如果您點選該存放區,會發現目前為空白。
設定存放區驗證機制
請使用下列指令,將應用程式預設憑證 (ADC) 的公開位置更新為使用者帳戶憑證,這樣在連線至存放區時,Artifact Registry 憑證輔助程式就能使用這些憑證進行驗證:
gcloud auth login --update-adc
為 Artifact Registry 設定 Maven
執行下列指令,即可列印要新增至 Java 專案的存放區設定:
gcloud artifacts print-settings mvn \
--repository=java-repo \
--location=us-central1 | tee config.xml
在 helloworld 目錄中,執行 Cloud Shell 中的下列指令,即可在 Cloud Shell 編輯器中開啟 pom.xml:
cloudshell edit pom.xml
並將傳回的設定新增至檔案中的適當部分。
更新 distributionManagement 部分
<distributionManagement>
<snapshotRepository>
<id>artifact-registry</id>
<url>artifactregistry://us-central1-maven.pkg.dev/<PROJECT>/java-repo</url>
</snapshotRepository>
<repository>
<id>artifact-registry</id>
<url>artifactregistry://us-central1-maven.pkg.dev/<PROJECT>/java-repo</url>
</repository>
</distributionManagement>
更新「存放區」部分
<repositories>
<repository>
<id>artifact-registry</id>
<url>artifactregistry://us-central1-maven.pkg.dev/<PROJECT>/java-repo</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
更新「build」下方的「extensions」部分
<extensions>
<extension>
<groupId>com.google.cloud.artifactregistry</groupId>
<artifactId>artifactregistry-maven-wagon</artifactId>
<version>2.1.0</version>
</extension>
</extensions>
以下是完整檔案的範例,供您參考。請務必將 <PROJECT> 替換為您的專案 ID。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.run</groupId>
<artifactId>helloworld</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>com.google.cloud.samples</groupId>
<artifactId>shared-configuration</artifactId>
<version>1.2.0</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.source>17</maven.compiler.source>
<spring-boot.version>3.2.2</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!-- [START Artifact Registry Config] -->
<distributionManagement>
<snapshotRepository>
<id>artifact-registry</id>
<url>artifactregistry://us-central1-maven.pkg.dev/<PROJECT>/java-repo</url>
</snapshotRepository>
<repository>
<id>artifact-registry</id>
<url>artifactregistry://us-central1-maven.pkg.dev/<PROJECT>/java-repo</url>
</repository>
</distributionManagement>
<repositories>
<repository>
<id>artifact-registry</id>
<url>artifactregistry://us-central1-maven.pkg.dev/<PROJECT>/java-repo</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<build>
<extensions>
<extension>
<groupId>com.google.cloud.artifactregistry</groupId>
<artifactId>artifactregistry-maven-wagon</artifactId>
<version>2.2.0</version>
</extension>
</extensions>
<!-- [END Artifact Registry Config] -->
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>3.4.0</version>
<configuration>
<to>
<image>gcr.io/PROJECT_ID/helloworld</image>
</to>
</configuration>
</plugin>
</plugins>
</build>
</project>
將 Java 套件上傳至 Artifact Registry
在 Maven 中設定 Artifact Registry 後,您現在可以使用 Artifact Registry 儲存 Java Jar,供貴機構的其他專案使用。
執行下列指令,將 Java 套件上傳至 Artifact Registry:
mvn deploy
在 Artifact Registry 中查看 Java 套件
前往 Cloud 控制台 - Artifact Registry - 存放區,按一下 java-repo
,確認 helloworld
二進位檔成果物是否存在:
9. 恭喜!
恭喜,您已完成程式碼研究室!
已涵蓋的內容
- 為容器和語言套件建立存放區
- 使用 Artifact Registry 管理容器映像檔
- 將 Artifact Registry 與 Cloud Code 整合
- 設定 Maven 使用 Artifact Registry 的 Java 依附元件
清除所用資源
在 Cloud Shell 中執行下列指令,即可刪除整個專案
gcloud projects delete $PROJECT_ID