1. Giriş
Genel Bakış
Bu codelab'de, kaynak kodu değişikliklerinizi GitHub deposuna her aktardığınızda uygulamanızın yeni sürümlerini otomatik olarak oluşturup dağıtacak şekilde Cloud Run'ı yapılandıracaksınız.
Bu demo uygulaması, kullanıcı verilerini Firestore'a kaydeder ancak verilerin yalnızca bir kısmı düzgün şekilde kaydedilir. Sürekli dağıtımları, GitHub deponuza bir hata düzeltmesi gönderdiğinizde düzeltmenin yeni bir düzeltmede otomatik olarak kullanılabilir hale gelecek şekilde yapılandıracaksınız.
Neler öğreneceksiniz?
- Cloud Shell Düzenleyici ile Express web uygulaması yazma
- Sürekli dağıtımlar için GitHub hesabınızı Google Cloud'a bağlama
- Uygulamanızı Cloud Run'a otomatik olarak dağıtma
- HTMX ve TailwindCSS'yi kullanmayı öğrenin
2. Kurulum ve Gereksinimler
Ön koşullar
- GitHub hesabınız olmalı ve depolarda kod oluşturup depolara kod aktarma konusunda bilgi sahibi olmalısınız.
- Cloud Console'a giriş yapmış olmanız gerekir.
- Daha önce bir Cloud Run hizmeti dağıtmış olmanız gerekir. Örneğin, başlamak için Kaynak koddan web hizmeti dağıtma hızlı başlangıç kılavuzunu inceleyebilirsiniz.
Cloud Shell'i etkinleştirme
- Cloud Console'da Cloud Shell'i etkinleştir 'i
tıklayın.

Cloud Shell'i ilk kez başlatıyorsanız ne olduğunu açıklayan bir ara ekran gösterilir. Ara ekran gösterildiyse Devam'ı tıklayın.

Cloud Shell'in temel hazırlığı ve bağlanması yalnızca birkaç dakikanızı alır.

Bu sanal makineye, ihtiyaç duyacağınız tüm geliştirme araçları yüklenmiştir. 5 GB boyutunda kalıcı bir ana dizin bulunur ve Google Cloud'da çalışır. Bu sayede ağ performansı ve kimlik doğrulama önemli ölçüde güçlenir. Bu codelab'deki çalışmalarınızın neredeyse tamamını tarayıcıyla yapabilirsiniz.
Cloud Shell'e bağlandıktan sonra kimliğinizin doğrulandığını ve projenin, proje kimliğinize ayarlandığını görürsünüz.
- Kimliğinizin doğrulandığını onaylamak için Cloud Shell'de şu komutu çalıştırın:
gcloud auth list
Komut çıkışı
Credentialed Accounts
ACTIVE ACCOUNT
* <my_account>@<my_domain.com>
To set the active account, run:
$ gcloud config set account `ACCOUNT`
- gcloud komutunun projeniz hakkında bilgi sahibi olduğunu onaylamak için Cloud Shell'de aşağıdaki komutu çalıştırın:
gcloud config list project
Komut çıkışı
[core] project = <PROJECT_ID>
Değilse şu komutla ayarlayabilirsiniz:
gcloud config set project <PROJECT_ID>
Komut çıkışı
Updated property [core/project].
3. API'leri etkinleştirme ve ortam değişkenlerini ayarlama
API'leri etkinleştir
Bu codelab'de aşağıdaki API'lerin kullanılması gerekir. Bu API'leri aşağıdaki komutu çalıştırarak etkinleştirebilirsiniz:
gcloud services enable run.googleapis.com \
cloudbuild.googleapis.com \
firestore.googleapis.com \
iamcredentials.googleapis.com
Ortam değişkenlerini ayarlama
Bu codelab boyunca kullanılacak ortam değişkenlerini ayarlayabilirsiniz.
REGION=<YOUR-REGION> PROJECT_ID=<YOUR-PROJECT-ID> PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)') SERVICE_ACCOUNT="firestore-accessor" SERVICE_ACCOUNT_ADDRESS=$SERVICE_ACCOUNT@$PROJECT_ID.iam.gserviceaccount.com
4. Hizmet hesabı oluşturma
Bu hizmet hesabı, Vertex AI Gemini API'yi çağırmak için Cloud Run tarafından kullanılır. Bu hizmet hesabı, Firestore'da okuma ve yazma işlemlerinin yanı sıra Secret Manager'dan gizli anahtarları okuma iznine de sahip olur.
Öncelikle şu komutu çalıştırarak hizmet hesabını oluşturun:
gcloud iam service-accounts create $SERVICE_ACCOUNT \ --display-name="Cloud Run access to Firestore"
Şimdi hizmet hesabına Firestore için okuma ve yazma erişimi verin.
gcloud projects add-iam-policy-binding $PROJECT_ID \ --member serviceAccount:$SERVICE_ACCOUNT_ADDRESS \ --role=roles/datastore.user
5. Firebase projesi oluşturma ve yapılandırma
- Firebase konsolunda Proje ekle'yi tıklayın.
- Firebase'i mevcut Google Cloud projelerinizden birine eklemek için <YOUR_PROJECT_ID> değerini girin.
- İstenirse Firebase şartlarını inceleyip kabul edin.
- Devam'ı tıklayın.
- Firebase faturalandırma planını onaylamak için Planı Onayla'yı tıklayın.
- Bu codelab için Google Analytics'i etkinleştirmek isteğe bağlıdır.
- Firebase ekle'yi tıklayın.
- Proje oluşturulduktan sonra Devam'ı tıklayın.
- Oluştur menüsünde Firestore veritabanı'nı tıklayın.
- Create database'i (Veritabanı oluştur) tıklayın.
- Konum açılır listesinden bölgenizi seçip Sonraki'yi tıklayın.
- Varsayılan Üretim modunda başlat seçeneğini kullanın ve Oluştur'u tıklayın.
6. Uygulamayı yazma
Öncelikle kaynak kodu için bir dizin oluşturun ve bu dizine gidin.
mkdir cloud-run-github-cd-demo && cd $_
Ardından, aşağıdaki içeriğe sahip bir package.json dosyası oluşturun:
{
"name": "cloud-run-github-cd-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node app.js",
"nodemon": "nodemon app.js",
"tailwind-dev": "npx tailwindcss -i ./input.css -o ./public/output.css --watch",
"tailwind": "npx tailwindcss -i ./input.css -o ./public/output.css",
"dev": "npm run tailwind && npm run nodemon"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@google-cloud/firestore": "^7.3.1",
"axios": "^1.6.7",
"express": "^4.18.2",
"htmx.org": "^1.9.10"
},
"devDependencies": {
"nodemon": "^3.1.0",
"tailwindcss": "^3.4.1"
}
}
Öncelikle aşağıdaki içeriğe sahip bir app.js kaynak dosyası oluşturun. Bu dosya, hizmetin giriş noktasını ve uygulamanın ana mantığını içerir.
const express = require("express");
const app = express();
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
const path = require("path");
const { get } = require("axios");
const { Firestore } = require("@google-cloud/firestore");
const firestoreDb = new Firestore();
const fs = require("fs");
const util = require("util");
const { spinnerSvg } = require("./spinnerSvg.js");
const service = process.env.K_SERVICE;
const revision = process.env.K_REVISION;
app.use(express.static("public"));
app.get("/edit", async (req, res) => {
res.send(`<form hx-post="/update" hx-target="this" hx-swap="outerHTML">
<div>
<p>
<label>Name</label>
<input class="border-2" type="text" name="name" value="Cloud">
</p><p>
<label>Town</label>
<input class="border-2" type="text" name="town" value="Nibelheim">
</p>
</div>
<div class="flex items-center mr-[10px] mt-[10px]">
<button class="btn bg-blue-500 text-white px-4 py-2 rounded-lg text-center text-sm font-medium mr-[10px]">Submit</button>
<button class="btn bg-gray-200 text-gray-800 px-4 py-2 rounded-lg text-center text-sm font-medium mr-[10px]" hx-get="cancel">Cancel</button>
${spinnerSvg}
</div>
</form>`);
});
app.post("/update", async function (req, res) {
let name = req.body.name;
let town = req.body.town;
const doc = firestoreDb.doc(`demo/${name}`);
//TODO: fix this bug
await doc.set({
name: name
/* town: town */
});
res.send(`<div hx-target="this" hx-swap="outerHTML" hx-indicator="spinner">
<p>
<div><label>Name</label>: ${name}</div>
</p><p>
<div><label>Town</label>: ${town}</div>
</p>
<button
hx-get="/edit"
class="bg-blue-500 text-white px-4 py-2 rounded-lg text-sm font-medium mt-[10px]"
>
Click to update
</button>
</div>`);
});
app.get("/cancel", (req, res) => {
res.send(`<div hx-target="this" hx-swap="outerHTML">
<p>
<div><label>Name</label>: Cloud</div>
</p><p>
<div><label>Town</label>: Nibelheim</div>
</p>
<div>
<button
hx-get="/edit"
class="bg-blue-500 text-white px-4 py-2 rounded-lg text-sm font-medium mt-[10px]"
>
Click to update
</button>
</div>
</div>`);
});
const port = parseInt(process.env.PORT) || 8080;
app.listen(port, async () => {
console.log(`booth demo: listening on port ${port}`);
//serviceMetadata = helper();
});
app.get("/helper", async (req, res) => {
let region = "";
let projectId = "";
let div = "";
try {
// Fetch the token to make a GCF to GCF call
const response1 = await get(
"http://metadata.google.internal/computeMetadata/v1/project/project-id",
{
headers: {
"Metadata-Flavor": "Google"
}
}
);
// Fetch the token to make a GCF to GCF call
const response2 = await get(
"http://metadata.google.internal/computeMetadata/v1/instance/region",
{
headers: {
"Metadata-Flavor": "Google"
}
}
);
projectId = response1.data;
let regionFull = response2.data;
const index = regionFull.lastIndexOf("/");
region = regionFull.substring(index + 1);
div = `
<div>
This created the revision <code>${revision}</code> of the
Cloud Run service <code>${service}</code> in <code>${region}</code>
for project <code>${projectId}</code>.
</div>`;
} catch (ex) {
// running locally
div = `<div> This is running locally.</div>`;
}
res.send(div);
});
spinnerSvg.js adlı bir dosya oluşturun.
module.exports.spinnerSvg = `<svg id="spinner" alt="Loading..."
class="htmx-indicator animate-spin -ml-1 mr-3 h-5 w-5 text-blue-500"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle
class="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
stroke-width="4"
></circle>
<path
class="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg>`;
TailwindCSS için input.css dosyası oluşturma
@tailwind base; @tailwind components; @tailwind utilities;
Ayrıca tailwindCSS için tailwind.config.js dosyasını oluşturun.
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./**/*.{html,js}"],
theme: {
extend: {}
},
plugins: []
};
.gitignore dosyası oluşturun.
node_modules/ npm-debug.log coverage/ package-lock.json .DS_Store
Şimdi yeni bir public dizini oluşturun.
mkdir public cd public
Bu herkese açık dizinde, kullanıcı arabirimi için index.html dosyasını oluşturun. Bu dosya htmx kullanır.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<script
src="https://unpkg.com/htmx.org@1.9.10"
integrity="sha384-D1Kt99CQMDuVetoL1lrYwg5t+9QdHe7NLX/SoJYkXDFfX37iInKRy5xLSi8nO7UC"
crossorigin="anonymous"
></script>
<link href="./output.css" rel="stylesheet" />
<title>Demo 1</title>
</head>
<body
class="font-sans bg-body-image bg-cover bg-center leading-relaxed"
>
<div class="container max-w-[700px] mt-[50px] ml-auto mr-auto">
<div class="hero flex items-center">
<div class="message text-base text-center mb-[24px]">
<h1 class="text-2xl font-bold mb-[10px]">
It's running!
</h1>
<div class="congrats text-base font-normal">
Congratulations, you successfully deployed your
service to Cloud Run.
</div>
</div>
</div>
<div class="details mb-[20px]">
<p>
<div hx-trigger="load" hx-get="/helper" hx-swap="innerHTML" hx-target="this">Hello</div>
</p>
</div>
<p
class="callout text-sm text-blue-700 font-bold pt-4 pr-6 pb-4 pl-10 leading-tight"
>
You can deploy any container to Cloud Run that listens for
HTTP requests on the port defined by the
<code>PORT</code> environment variable. Cloud Run will
scale automatically based on requests and you never have to
worry about infrastructure.
</p>
<h1 class="text-2xl font-bold mt-[40px] mb-[20px]">
Persistent Storage Example using Firestore
</h1>
<div hx-target="this" hx-swap="outerHTML">
<p>
<div><label>Name</label>: Cloud</div>
</p><p>
<div><label>Town</label>: Nibelheim</div>
</p>
<div>
<button
hx-get="/edit"
class="bg-blue-500 text-white px-4 py-2 rounded-lg text-sm font-medium mt-[10px]"
>
Click to update
</button>
</div>
</div>
<h1 class="text-2xl font-bold mt-[40px] mb-[20px]">
What's next
</h1>
<p class="next text-base mt-4 mb-[20px]">
You can build this demo yourself!
</p>
<p class="cta">
<button
class="bg-blue-500 text-white px-4 py-2 rounded-lg text-center text-sm font-medium"
>
VIEW CODELAB
</button>
</p>
</div>
</body>
</html>
7. Uygulamayı yerel olarak çalıştırma
Bu bölümde, kullanıcı verileri kaydetmeye çalıştığında uygulamada bir hata olduğunu doğrulamak için uygulamayı yerel olarak çalıştıracaksınız.
Öncelikle Firestore'a erişmek için Datastore Kullanıcısı rolüne sahip olmanız (kimliğinizi kimlik doğrulama için kullanıyorsanız, örneğin Cloud Shell'de çalışıyorsanız) veya daha önce oluşturulan kullanıcı hesabının kimliğine bürünmeniz gerekir.
Yerel olarak çalıştırırken ADC'yi kullanma
Cloud Shell'de çalışıyorsanız zaten bir Google Compute Engine sanal makinesinde çalışıyorsunuzdur. Bu sanal makineyle ilişkili kimlik bilgileriniz (gcloud auth list çalıştırılarak gösterildiği gibi) Uygulama Varsayılan Kimlik Bilgileri (ADC) tarafından otomatik olarak kullanılacağından gcloud auth application-default login komutunu kullanmanız gerekmez. Ancak kimliğinizin Datastore Kullanıcısı rolüne sahip olması gerekir. Uygulamayı yerel olarak çalıştırma bölümüne atlayabilirsiniz.
Ancak yerel terminalinizde (ör. Cloud Shell'de değil) çalışıyorsanız Google API'lerinde kimlik doğrulaması yapmak için Uygulama Varsayılan Kimlik Bilgileri'ni kullanmanız gerekir. 1) Kimlik bilgilerinizi kullanarak giriş yapabilir (Datastore Kullanıcısı rolüne sahip olmanız gerekir) veya 2) bu codelab'de kullanılan hizmet hesabının kimliğine bürünerek giriş yapabilirsiniz.
1. seçenek: ADC için kimlik bilgilerinizi kullanma
Kimlik bilgilerinizi kullanmak istiyorsanız öncelikle gcloud auth list komutunu çalıştırarak gcloud'da nasıl kimlik doğrulandığınızı doğrulayabilirsiniz. Ardından, kimliğinize Vertex AI Kullanıcısı rolünü vermeniz gerekebilir. Kimliğinizde Sahip rolü varsa bu Datastore Kullanıcısı kullanıcı rolüne zaten sahipsinizdir. Aksi takdirde, kimliğinize Vertex AI kullanıcı rolü ve veri deposu kullanıcı rolü vermek için bu komutu çalıştırabilirsiniz.
USER=<YOUR_PRINCIPAL_EMAIL> gcloud projects add-iam-policy-binding $PROJECT_ID \ --member user:$USER \ --role=roles/datastore.user
Ardından aşağıdaki komutu çalıştırın.
gcloud auth application-default login
2. seçenek: ADC için bir hizmet hesabının kimliğine bürünme
Bu codelab'de oluşturulan hizmet hesabını kullanmak istiyorsanız kullanıcı hesabınızın Hizmet Hesabı Jetonu Oluşturucu rolüne sahip olması gerekir. Bu rolü aşağıdaki komutu çalıştırarak edinebilirsiniz:
gcloud projects add-iam-policy-binding $PROJECT_ID \ --member user:$USER \ --role=roles/iam.serviceAccountTokenCreator
Ardından, hizmet hesabıyla ADC'yi kullanmak için aşağıdaki komutu çalıştıracaksınız.
gcloud auth application-default login --impersonate-service-account=$SERVICE_ACCOUNT_ADDRESS
Uygulamayı yerel olarak çalıştırma
Ardından, kod laboratuvarınızın kök dizininde cloud-run-github-cd-demo olduğunuzdan emin olun.
cd .. && pwd
Şimdi bağımlılıkları yükleyeceksiniz.
npm install
Son olarak, aşağıdaki komut dosyasını çalıştırarak uygulamayı başlatabilirsiniz. Bu komut dosyası, tailwindCSS'den output.css dosyasını da oluşturur.
npm run dev
Şimdi web tarayıcınızda http://localhost:8080 adresini açın. Cloud Shell'deyseniz Web Önizlemesi düğmesini açıp 8080 numaralı bağlantı noktasında önizle'yi seçerek web sitesini açabilirsiniz.

Ad ve şehir giriş alanlarına metin girip kaydet'e basın. Ardından sayfayı yenileyin. Şehir alanının kalıcı olmadığını fark edeceksiniz. Bu hatayı sonraki bölümde düzelteceksiniz.
Express uygulamasının yerel olarak çalışmasını durdurun (ör. MacOS'te Ctrl^c).
8. GitHub deposu oluşturma
Yerel dizininizde, varsayılan dal adı olarak main'i kullanan yeni bir depo oluşturun.
git init git branch -M main
Hatayı içeren mevcut kod tabanını işleyin. Sürekli dağıtım yapılandırıldıktan sonra hatayı düzeltirsiniz.
git add . git commit -m "first commit for express application"
GitHub'a gidip size özel veya herkese açık olan boş bir depo oluşturun. Bu codelab'de, deponuzu cloud-run-auto-deploy-codelab olarak adlandırmanız önerilir. Boş bir depo oluşturmak için tüm varsayılan ayarları işaretlenmemiş veya "yok" olarak bırakırsınız. Böylece, oluşturulduğunda depoda varsayılan olarak hiçbir içerik bulunmaz. Örneğin:

Bu adımı doğru şekilde tamamladıysanız boş depolama alanı sayfasında aşağıdaki talimatları görürsünüz:

Aşağıdaki komutları çalıştırarak mevcut bir depoyu komut satırından gönderme talimatlarını uygulayacaksınız:
Öncelikle, aşağıdaki komutu çalıştırarak uzak depoyu ekleyin:
git remote add origin <YOUR-REPO-URL-PER-GITHUB-INSTRUCTIONS>
Ardından ana dalı yukarı akış deposuna gönderin.
git push -u origin main
9. Sürekli Dağıtımı ayarlama
GitHub'da kodunuz olduğuna göre artık sürekli dağıtımı ayarlayabilirsiniz. Cloud Run için Cloud Console'a gidin.
- Hizmet Oluştur'u tıklayın.
- Depodan sürekli olarak dağıt'ı tıklayın.
- SET UP CLOUD BUILD'u (CLOUD BUILD'U AYARLA) tıklayın.
- Kaynak kod deposu bölümünde
- Depo sağlayıcı olarak GitHub'ı seçin
- Depoya Cloud Build erişimini yapılandırmak için Bağlı depoları yönet'i tıklayın.
- Deponuzu seçin ve İleri'yi tıklayın.
- Yapılandırma Oluşturma bölümünde
- Leave Branch as ^main$
- Derleme Türü için Google Cloud'un buildpack'leri aracılığıyla Go, Node.js, Python, Java, .NET Core, Ruby veya PHP'yi seçin.
- Derleme bağlamı dizinini
/olarak bırakın. - Kaydet'i tıklayın
- Kimlik Doğrulama bölümünde
- Kimliği doğrulanmayan çağrılara izin ver'i tıklayın.
- Container(s), Volumes, Networking, Security (Container'lar, Birimler, Ağ, Güvenlik) bölümünde
- Güvenlik sekmesinde, önceki bir adımda oluşturduğunuz hizmet hesabını seçin (ör.
Cloud Run access to Firestore).
- Güvenlik sekmesinde, önceki bir adımda oluşturduğunuz hizmet hesabını seçin (ör.
- OLUŞTUR'u tıklayın.
Bu işlem, bir sonraki bölümde düzelteceğiniz hatayı içeren Cloud Run hizmetini dağıtır.
10. Hatayı düzeltme
Koddaki hatayı düzeltin
Cloud Shell Düzenleyici'de app.js dosyasını açın ve //TODO: fix this bug yorumuna gidin.
Aşağıdaki satırı
//TODO: fix this bug
await doc.set({
name: name
});
to
//fixed town bug
await doc.set({
name: name,
town: town
});
Aşağıdaki komutu çalıştırarak düzeltmeyi doğrulayın:
npm run start
ve web tarayıcınızı açın. Kasaba için verileri tekrar kaydedin ve yenileyin. Yeni girilen şehir verilerinin yenileme işleminden sonra doğru şekilde kalıcı hale geldiğini görürsünüz.
Düzeltmenizi doğruladığınıza göre artık dağıtabilirsiniz. Öncelikle düzeltmeyi işleyin.
git add . git commit -m "fixed town bug"
ve ardından GitHub'daki yukarı akış deposuna aktarın.
git push origin main
Cloud Build, değişikliklerinizi otomatik olarak dağıtır. Dağıtım değişikliklerini izlemek için Cloud Run hizmetinizin Cloud Console'una gidebilirsiniz.
Düzeltmeyi üretimde doğrulama
Cloud Run hizmetinizin Cloud Console'unda artık trafiğin% 100'ünün 2.düzeltme tarafından sunulduğu gösterildiğinde (ör. https://console.cloud.google.com/run/detail/<YOUR_REGION>/<YOUR_SERVICE_NAME>/revisions), Cloud Run hizmeti URL'sini tarayıcınızda açabilir ve sayfayı yeniledikten sonra yeni girilen şehir verilerinin kalıcı hale geldiğini doğrulayabilirsiniz.
11. Tebrikler!
Tebrikler, codelab'i tamamladınız.
Cloud Run ve git'ten sürekli dağıtım dokümanlarını incelemenizi öneririz.
İşlediğimiz konular
- Cloud Shell Düzenleyici ile Express web uygulaması yazma
- Sürekli dağıtımlar için GitHub hesabınızı Google Cloud'a bağlama
- Uygulamanızı Cloud Run'a otomatik olarak dağıtma
- HTMX ve TailwindCSS'yi kullanmayı öğrenin
12. Temizleme
Yanlışlıkla ücretlendirilmemek için (örneğin, Cloud Run hizmetleri ücretsiz katmandaki aylık Cloud Run çağırma kotanızdan daha fazla sayıda çağrılırsa) Cloud Run'ı veya 2. adımda oluşturduğunuz projeyi silebilirsiniz.
Cloud Run hizmetini silmek için https://console.cloud.google.com/run adresinden Cloud Run Cloud Console'a gidin ve bu codelab'de oluşturduğunuz Cloud Run hizmetini silin (ör. cloud-run-auto-deploy-codelab hizmetini silin).
Projenin tamamını silmeyi tercih ederseniz https://console.cloud.google.com/cloud-resource-manager adresine gidebilir, 2. adımda oluşturduğunuz projeyi seçip Sil'i tıklayabilirsiniz. Projeyi silerseniz Cloud SDK'nızda projeleri değiştirmeniz gerekir. gcloud projects list komutunu çalıştırarak kullanılabilir tüm projelerin listesini görüntüleyebilirsiniz.