Artifact Registry के बारे में ज़्यादा जानकारी

1. खास जानकारी

कंटेनर रजिस्ट्री के बेहतर वर्शन के तौर पर, Artifact Registry एक ऐसा प्लैटफ़ॉर्म है जहां आपका संगठन, कंटेनर इमेज और भाषा के पैकेज (जैसे, Maven और एनपीएम) को मैनेज कर सकता है. इसे Google Cloud के टूल और रनटाइम के साथ पूरी तरह से इंटिग्रेट किया गया है. साथ ही, इसमें भाषा के हिसाब से डिपेंडेंसी मैनेज करने की सुविधा मिलती है. इसका इस्तेमाल npm और Maven जैसे टूल के साथ किया जाता है. इसकी मदद से, ऑटोमेटेड पाइपलाइन सेट अप करने के लिए, इसे CI/CD टूल के साथ आसानी से इंटिग्रेट किया जा सकता है.

यह लैब आपको Artifact Registry में उपलब्ध कुछ सुविधाओं के बारे में जानकारी देगी.

आपको क्या सीखने को मिलेगा

इस लैब के सीखने के मकसद क्या हैं?

  • कंटेनर और भाषा पैकेज के लिए डेटा स्टोर करने की जगहें बनाना
  • Artifact Registry की मदद से कंटेनर इमेज मैनेज करें
  • Artifact Registry को Cloud कोड के साथ इंटिग्रेट करना
  • Java डिपेंडेंसी के लिए Artifact Registry का इस्तेमाल करने के लिए, Maven को कॉन्फ़िगर करें

2. सेटअप और ज़रूरी शर्तें

अपने हिसाब से एनवायरमेंट सेटअप करें

  1. Google Cloud Console में साइन इन करें और नया प्रोजेक्ट बनाएं या किसी मौजूदा प्रोजेक्ट का फिर से इस्तेमाल करें. अगर आपके पास पहले से Gmail या Google Workspace खाता नहीं है, तो आपको नया खाता बनाना होगा.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • प्रोजेक्ट का नाम, इस प्रोजेक्ट में हिस्सा लेने वाले लोगों का डिसप्ले नेम होता है. यह एक वर्ण स्ट्रिंग है, जिसका इस्तेमाल Google API नहीं करता. साथ ही, आप इसे किसी भी समय अपडेट कर सकते हैं.
  • प्रोजेक्ट आईडी, Google Cloud के सभी प्रोजेक्ट के लिए यूनीक होना चाहिए. साथ ही, आईडी को बदला नहीं जा सकता. सेट अप के बाद इसे बदला नहीं जा सकता. Cloud Console, एक यूनीक स्ट्रिंग अपने-आप जनरेट करता है; आम तौर पर, आपको उसके होने की कोई परवाह नहीं होती. ज़्यादातर कोडलैब में, आपको प्रोजेक्ट आईडी का रेफ़रंस देना पड़ता है और आम तौर पर इसकी पहचान PROJECT_ID के रूप में की जाती है. इसलिए, अगर आपको यह पसंद नहीं आता है, तो कोई भी कोड जनरेट करें. इसके अलावा, खुद का भी कोड बनाकर देखा जा सकता है कि वह उपलब्ध है या नहीं. फिर यह "फ़्रोज़न" होता है प्रोजेक्ट बनने के बाद.
  • तीसरी वैल्यू, प्रोजेक्ट नंबर है, जिसका इस्तेमाल कुछ एपीआई करते हैं. दस्तावेज़ में इन तीनों वैल्यू के बारे में ज़्यादा जानें.
  1. इसके बाद, आपको क्लाउड संसाधनों/एपीआई का इस्तेमाल करने के लिए, Cloud Console में बिलिंग की सुविधा चालू करनी होगी. इस कोडलैब का इस्तेमाल करने पर, आपको ज़्यादा पैसे नहीं चुकाने होंगे. इस ट्यूटोरियल के अलावा किसी अन्य प्लैटफ़ॉर्म पर बिलिंग न करने के लिए, संसाधनों को बंद करने के लिए, "साफ़-सफ़ाई" का पालन करें कोडलैब के आखिर में दिए गए निर्देश देखें. Google Cloud के नए उपयोगकर्ता, 300 डॉलर के मुफ़्त ट्रायल वाले प्रोग्राम में हिस्सा ले सकते हैं.

gcloud सेट अप करें

Cloud Shell में, अपना प्रोजेक्ट आईडी और प्रोजेक्ट नंबर सेट करें. उन्हें 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 \
  container.googleapis.com \
  artifactregistry.googleapis.com \
  containerregistry.googleapis.com \
  containerscanning.googleapis.com

सोर्स कोड पाएं

इस लैब का सोर्स कोड, GitHub पर GoogleCloudPlatform संगठन में मौजूद है. नीचे दिए गए निर्देश से इसे क्लोन करें और फिर डायरेक्ट्री में बदलें.

git clone https://github.com/GoogleCloudPlatform/cloud-code-samples/

इस लैब में इस्तेमाल किए जा रहे इन्फ़्रास्ट्रक्चर का प्रावधान करें

इस लैब में, आपको GKE (जीकेई) पर कोड डिप्लॉय करना होगा. नीचे दी गई सेटअप स्क्रिप्ट आपके लिए यह इन्फ़्रास्ट्रक्चर तैयार करती है.

gcloud container clusters create container-dev-cluster --zone=us-central1-b

3. कंटेनर इमेज के साथ काम करना

आर्टफ़ैक्ट रजिस्ट्री पर Docker डेटा स्टोर करने की जगह बनाएं

Artifact Registry, कंटेनर की इमेज और भाषा के पैकेज को मैनेज करने की सुविधा देती है. अलग-अलग तरह के आर्टफ़ैक्ट के लिए, अलग-अलग खास निर्देशों की ज़रूरत होती है. उदाहरण के लिए, Maven डिपेंडेंसी के अनुरोध, नोड डिपेंडेंसी के अनुरोधों से अलग होते हैं.

अलग-अलग एपीआई की खास बातों के साथ काम करने के लिए, Artifact Registry को यह जानना होगा कि एपीआई से मिलने वाले जवाबों को किस फ़ॉर्मैट में सबमिट करना है. ऐसा करने के लिए, आपको एक रिपॉज़िटरी बनाना होगा और --repository-format फ़्लैग में पास करना होगा. इससे यह पता चलेगा कि आपको किस तरह का डेटा स्टोर करना है

Docker इमेज का डेटा स्टोर करने की जगह बनाने के लिए, Cloud Shell से यह कमांड चलाएं:

gcloud artifacts repositories create container-dev-repo --repository-format=docker \
--location=us-central1 --description="Docker repository for Container Dev Workshop"

अगर Cloud Shell से अनुमति देने का अनुरोध दिखता है, तो 'अनुमति दें' पर क्लिक करें

Google Cloud Console - Artifact Registry - डेटा स्टोर करने की जगहों पर जाएं और देखें कि container-dev-repo नाम का नया Docker डेटा स्टोर करने की जगह पर जाएं. इस पर क्लिक करने पर आपको दिखेगा कि फ़िलहाल यह खाली है

Artifact Registry में, Docker की पुष्टि करने की सुविधा को कॉन्फ़िगर करना

ऐक्सेस देने के लिए, Artifact Registry के क्रेडेंशियल से कनेक्ट करना ज़रूरी होता है. अलग-अलग क्रेडेंशियल सेट अप करने के बजाय, Docker को आपके gcloud क्रेडेंशियल आसानी से इस्तेमाल करने के लिए कॉन्फ़िगर किया जा सकता है.

Cloud Shell से, Docker को कॉन्फ़िगर करने के लिए यह कमांड चलाएं, ताकि Google Cloud सीएलआई का इस्तेमाल करके us-central1 क्षेत्र में Artifact Registry के अनुरोधों की पुष्टि की जा सके.

gcloud auth configure-docker us-central1-docker.pkg.dev

इस निर्देश में, Cloud Shell के डॉकर का कॉन्फ़िगरेशन बदलने की पुष्टि करने के लिए कहा जाएगा. इसके बाद, Enter दबाएं.

ऐप्लिकेशन का नमूना एक्सप्लोर करें

उस git रिपॉज़िटरी में ऐप्लिकेशन का सैंपल दिया गया है जिसे आपने पिछले चरण में क्लोन किया था. Java डायरेक्ट्री में बदलाव करें और ऐप्लिकेशन कोड की समीक्षा करें.

cd cloud-code-samples/java/java-hello-world

इस फ़ोल्डर में एक उदाहरण Java ऐप्लिकेशन मौजूद है, जो किसी सामान्य वेब पेज को रेंडर करता है: इस खास लैब के लिए काम की न होने वाली कई फ़ाइलों के अलावा, इसमें src फ़ोल्डर के तहत सोर्स कोड होता है. साथ ही, एक Dockerfile भी मौजूद होती है, जिसका इस्तेमाल हम स्थानीय तौर पर कंटेनर इमेज बनाने के लिए करेंगे.

कंटेनर की इमेज बनाएं

कंटेनर इमेज को Artifact Registry में स्टोर करने से पहले, आपको एक इमेज बनानी होगी.

कंटेनर इमेज बनाने के लिए, नीचे दिया गया कमांड चलाएं. साथ ही, अगले चरण में इसे ठीक से अपने रिपॉज़िटरी में पुश करने के लिए टैग करें:

docker build -t us-central1-docker.pkg.dev/$PROJECT_ID/container-dev-repo/java-hello-world:tag1 .

कंटेनर इमेज को Artifact Registry में भेजना

कंटेनर इमेज को पहले बनाए गए डेटा स्टोर करने की जगह में पुश करने के लिए, नीचे दिया गया कमांड चलाएं:

docker push us-central1-docker.pkg.dev/$PROJECT_ID/container-dev-repo/java-hello-world:tag1

Artifact Registry में मौजूद इमेज की समीक्षा करना

Google Cloud Console - Artifact Registry - Repositories पर जाएं. container-dev-repo पर क्लिक करें और देखें कि java-hello-world इमेज वहां मौजूद है या नहीं. इमेज पर क्लिक करें और टैग की गई tag1 इमेज को नोट करें. आप देख सकते हैं कि जोखिम की आशंका की जांच चल रही है या यह जांच पहले ही पूरी हो चुकी है. साथ ही, जोखिम की आशंकाओं की संख्या दिख रही है.

9cb46d3689b3ed2.png

जोखिम की आशंकाओं की संख्या पर क्लिक करें. इसके बाद, आपको इमेज में मिली जोखिम की आशंकाओं की सूची, CVE बुलेटिन नाम और गंभीरता के साथ दिखेगी. ज़्यादा जानकारी के लिए, सूची में शामिल हर जोखिम के बारे में 'देखें' पर क्लिक करें:

2b17e9d26d9dd7ea.png

4. Cloud Code के साथ इंटिग्रेशन

इस सेक्शन में, आपको Cloud Code के साथ Artifact Registry के Docker इमेज रिपॉज़िटरी को इस्तेमाल करने का तरीका बताया जाएगा.

ऐप्लिकेशन को Cloud Code से GKE (जीकेई) क्लस्टर में डिप्लॉय करें

Cloud Shell Editor खोलने और ऐप्लिकेशन फ़ोल्डर को उसके फ़ाइल फ़ोल्डर में जोड़ने के लिए, java-hello-world फ़ोल्डर से यह निर्देश चलाएं:

cloudshell workspace .

क्लाउड शेल एडिटर, ऐप्लिकेशन फ़ोल्डर में एक्सप्लोरर के साथ खुलेगा.

अगर आपको पॉप-अप दिखता है, जिसमें फ़ाइल फ़ोल्डर से Java प्रोजेक्ट सेटिंग फ़ाइलों को शामिल न करने के लिए कहा जाता है, तो Exclude in workspace पर क्लिक करें

नीचे दिए गए तरीके का इस्तेमाल करने पर, आपको Artifact Registry के रिपॉज़िटरी (डेटा स्टोर करने की जगह) की जगह की जानकारी डालनी होगी. जगह का फ़ॉर्मैट यह है:

us-central1-docker.pkg.dev/<PROJECT_ID>/container-dev-repo

अपना PROJECT_ID ढूंढने के लिए टर्मिनल में नीचे दिया गया निर्देश चलाएं

gcloud config get project

Cloud Code स्थिति बार (नीचे बाएं कोने में) पर क्लिक करें और फिर Run on Kubernetes चुनें

e6e2b06467228e18.png

जब कहा जाए, तब kubeconfig में मौजूदा कॉन्टेक्स्ट का इस्तेमाल करने के लिए Yes को चुनें. यह कॉन्टेक्स्ट, लैब के लिए प्रावधान किए गए container-dev-cluster GKE (जीकेई) क्लस्टर पर ले जाता है

इमेज रजिस्ट्री के प्रॉम्प्ट में, <PROJECT_ID> की जगह कोई दूसरा प्रोजेक्ट जोड़ने से पहले, अपने पते की जगह डालें अपने असल मान के लिए

us-central1-docker.pkg.dev/<PROJECT_ID>/container-dev-repo

जब Cloud Code पर पहली बार Kubernetes पर चलाएं, तो आपको टारगेट की गई इमेज का डेटा स्टोर करने की जगह बताने के लिए प्रॉम्प्ट किया जाता है. एक बार दिए जाने के बाद, रिपॉज़िटरी यूआरएल को .vscode/launch.json फ़ाइल में सेव कर लिया जाता है, जो ऐप्लिकेशन फ़ोल्डर में बनाई जाती है.

आउटपुट पैनल में आपको दिखता है कि ऐप्लिकेशन इमेज के लिए बिल्ड शुरू हो रहा है java-hello-world, इमेज को पहले कॉन्फ़िगर किए गए Artifact Registry के डेटा स्टोर करने की जगह में अपलोड किया जा चुका है

Cloud Console - Artifact Registry - Repositories पर जाएं. container-dev-repo पर क्लिक करके देखें कि java-hello-world इमेज और टैग की गई नई इमेज latest को नोट करें

डिप्लॉय किए गए ऐप्लिकेशन की समीक्षा करें

क्लाउड शेल एडिटर पर वापस जाएं: डिप्लॉयमेंट पूरा हो जाने के बाद, Skaffold/Cloud Code, बिना अनुमति के सार्वजनिक यूआरएल को प्रिंट कर देंगे, जहां सेवा फ़ॉरवर्ड की गई है, लिंक पर क्लिक करें - Web Preview खोलें:

33257a43826b88ff.png

नई ब्राउज़र विंडो में आपको hello World ऐप्लिकेशन पेज दिखेगा

d3e49693b0383a5d.png

ऐप्लिकेशन कोड अपडेट करें

क्लस्टर पर डिप्लॉयमेंट में तुरंत लागू किए गए बदलाव को देखने के लिए, ऐप्लिकेशन को अब अपडेट करें:

HelloWorldController.java को Cloud Shell Editor में, src/main/java/cloudcode/helloworld/web फ़ोल्डर में खोलें.

पंक्ति 20 के टेक्स्ट को "यह चल रहा है!" से बदलें. "इसे अपडेट कर दिया गया है!"" पर, बिल्ड और डिप्लॉयमेंट की प्रोसेस तुरंत शुरू हो जाएगी.

डिप्लॉयमेंट के खत्म होने पर, फ़ॉरवर्ड किए गए यूआरएल पर फिर से क्लिक करें या लागू किए गए अपने बदलाव को देखने के लिए, ब्राउज़र विंडो को ऐप्लिकेशन से रीफ़्रेश करें:

41787b1da54ff137.png

फिर से Cloud Console - Artifact Registry - Repositories पर जाएं. container-dev-repo पर क्लिक करें और देखें कि java-hello-world इमेज और नई इमेज नोट करें

5. भाषा पैकेज के साथ काम करना

इस सेक्शन में, आपको Artifact Registry के Java डेटा स्टोर करने की जगह सेट अप करने और अलग-अलग ऐप्लिकेशन में पैकेज अपलोड करने का तरीका बताया गया है.

Java पैकेज डेटा स्टोर करने की जगह बनाना

Java आर्टफ़ैक्ट का डेटा स्टोर करने की जगह बनाने के लिए, Cloud Shell से यह कमांड चलाएं:

gcloud artifacts repositories create container-dev-java-repo \
    --repository-format=maven \
    --location=us-central1 \
    --description="Java package repository for Container Dev Workshop"

अगर Cloud Shell से अनुमति देने का अनुरोध दिखता है, तो 'अनुमति दें' पर क्लिक करें

Google Cloud Console - Artifact Registry - डेटा स्टोर करने की जगहों पर जाएं और देखें कि container-dev-java-repo नाम का Maven रिपॉज़िटरी हाल ही में बनाया गया है. इस पर क्लिक करने पर देखें कि फ़िलहाल वह खाली है या नहीं.

आर्टफ़ैक्ट स्टोर करने की जगह के लिए पुष्टि करने की सुविधा सेट अप करना

ऐप्लिकेशन के डिफ़ॉल्ट क्रेडेंशियल (एडीसी) के लिए जानी-मानी जगह की जानकारी को अपने उपयोगकर्ता खाते के क्रेडेंशियल से अपडेट करने के लिए, नीचे दिए गए निर्देश का इस्तेमाल करें. इससे, डेटा स्टोर करने की जगहों से कनेक्ट करते समय, Artifact Registry के क्रेडेंशियल का हेल्पर उनके इस्तेमाल की पुष्टि कर सकेगा:

gcloud auth login --update-adc

Artifact Registry के लिए, Maven को कॉन्फ़िगर करना

अपने Java प्रोजेक्ट में डेटा स्टोर करने की जगह का कॉन्फ़िगरेशन जोड़ने के लिए, यह कमांड चलाएं:

gcloud artifacts print-settings mvn \
    --repository=container-dev-java-repo \
    --location=us-central1

Cloud Shell Editor में pom.xml खोलें और दिखाई गई सेटिंग को फ़ाइल के सही सेक्शन में जोड़ें.

distributionManagement सेक्शन को अपडेट करना

<distributionManagement>
   <snapshotRepository>
     <id>artifact-registry</id>
     <url>artifactregistry://us-central1-maven.pkg.dev/<PROJECT>/container-dev-java-repo</url>
   </snapshotRepository>
   <repository>
     <id>artifact-registry</id>
     <url>artifactregistry://us-central1-maven.pkg.dev/<PROJECT>/container-dev-java-repo</url>
   </repository>
</distributionManagement>

डेटा स्टोर करने की जगह सेक्शन को अपडेट करें

 <repositories>
   <repository>
     <id>artifact-registry</id>
     <url>artifactregistry://us-central1-maven.pkg.dev/<PROJECT>/container-dev-java-repo</url>
     <releases>
       <enabled>true</enabled>
     </releases>
     <snapshots>
       <enabled>true</enabled>
     </snapshots>
   </repository>
 </repositories>

एक्सटेंशन अपडेट करें

<extensions>
     <extension>
       <groupId>com.google.cloud.artifactregistry</groupId>
       <artifactId>artifactregistry-maven-wagon</artifactId>
       <version>2.1.0</version>
     </extension>
   </extensions>

यहां आपकी जानकारी के लिए पूरी फ़ाइल का एक उदाहरण दिया गया है. <PROJECT> को बदलना पक्का करें को अपने प्रोजेक्ट आईडी से जोड़ें.

<?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>
 
 <artifactId>hello-world</artifactId>
 <packaging>jar</packaging>
 <name>Cloud Code Hello World</name>
 <description>Getting started with Cloud Code</description>
 <version>1.0.0</version>
<distributionManagement>
   <snapshotRepository>
     <id>artifact-registry</id>
     <url>artifactregistry://us-central1-maven.pkg.dev/<PROJECT>/container-dev-java-repo</url>
   </snapshotRepository>
   <repository>
     <id>artifact-registry</id>
     <url>artifactregistry://us-central1-maven.pkg.dev/<PROJECT>/container-dev-java-repo</url>
   </repository>
 </distributionManagement>
 
 <repositories>
   <repository>
     <id>artifact-registry</id>
     <url>artifactregistry://us-central1-maven.pkg.dev/<PROJECT>/container-dev-java-repo</url>
     <releases>
       <enabled>true</enabled>
     </releases>
     <snapshots>
       <enabled>true</enabled>
     </snapshots>
   </repository>
 </repositories>
 
 <parent>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-parent</artifactId>
   <version>2.6.3</version>
 </parent>
 
 <properties>
   <java.version>1.8</java.version>
   <checkstyle.config.location>./checkstyle.xml</checkstyle.config.location>
 </properties>
 
 <build>
   <plugins>
     <plugin>
       <groupId>com.google.cloud.tools</groupId>
       <artifactId>jib-maven-plugin</artifactId>
       <version>3.2.0</version>
     </plugin>
     <plugin>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-maven-plugin</artifactId>
     </plugin>
     <plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-checkstyle-plugin</artifactId>
       <version>3.1.2</version>
     </plugin>
   </plugins>
   <extensions>
     <extension>
       <groupId>com.google.cloud.artifactregistry</groupId>
       <artifactId>artifactregistry-maven-wagon</artifactId>
       <version>2.1.0</version>
     </extension>
   </extensions>
 </build>
 
 <!-- The Spring Cloud GCP BOM will manage spring-cloud-gcp version numbers for you. -->
 <dependencyManagement>
   <dependencies>
     <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-gcp-dependencies</artifactId>
       <version>1.2.8.RELEASE</version>
       <type>pom</type>
       <scope>import</scope>
     </dependency>
   </dependencies>
 </dependencyManagement>
  
 <dependencies>
 
   <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter</artifactId>
   </dependency>
 
   <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-jetty</artifactId>
   </dependency>
 
   <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-webmvc</artifactId>
   </dependency>
 
   <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-thymeleaf</artifactId>
   </dependency>
 
   <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-test</artifactId>
     <scope>test</scope>
   </dependency>
 
   <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-gcp-starter-logging</artifactId>
   </dependency>
      
 </dependencies>
 
</project>

Artifact Registry में अपना Java पैकेज अपलोड करें

Maven में Artifact Registry को कॉन्फ़िगर करके, अब Artifact Registry का इस्तेमाल किया जा सकता है.

Artifact Registry में अपना Java पैकेज अपलोड करने के लिए, नीचे दिया गया कमांड चलाएं:

mvn deploy

Artifact Registry में जाकर Java पैकेज देखें

Cloud Console - Artifact Registry - Repositories पर जाएं. container-dev-java-repo पर क्लिक करके देखें कि hello-world बाइनरी आर्टफ़ैक्ट तो नहीं है:

e348d976ac1ac107.png

6. बधाई हो!

बधाई हो, आपने कोडलैब पूरा कर लिया है!

आपने क्या कवर किया

  • कंटेनर और भाषा पैकेज के लिए डेटा स्टोर करने की जगहें बनाई गईं
  • Artifact Registry वाली मैनेज की जा रही कंटेनर इमेज
  • Cloud Code के साथ इंटिग्रेट की गई Artifact Registry
  • Java डिपेंडेंसी के लिए Artifact Registry का इस्तेमाल करने के लिए, Maven को कॉन्फ़िगर किया गया है

साफ़-सफ़ाई सेवा

प्रोजेक्ट मिटाने के लिए, यहां दिया गया कमांड चलाएं

gcloud projects delete $PROJECT_ID