이 Codelab 정보
1. 소개
최종 업데이트: 2024년 11월 1일
오래된 PHP 애플리케이션을 Google Cloud로 현대화하려면 어떻게 해야 하나요?
(📽️ 이 Codelab의 7분 소개 동영상 을 시청하세요)
현대화해야 하는 기존 애플리케이션이 온프레미스에서 실행되는 경우가 많습니다. 즉, 확장 가능하고 안전하며 다양한 환경에 배포할 수 있어야 합니다.
이 워크숍에서는 다음을 수행합니다.
- PHP 애플리케이션을 컨테이너화합니다.
- 관리형 데이터베이스 서비스 ( Cloud SQL)로 이동합니다.
- Cloud Run에 배포합니다 (GKE/Kubernetes의 제로 운영 대안).
- Identity and Access Management (IAM) 및 Secret Manager로 애플리케이션을 보안합니다.
- Cloud Build를 통해 CI/CD 파이프라인을 정의합니다. Cloud Build는 GitHub 또는 GitLab과 같은 인기 Git 제공업체에서 호스팅되는 Git 저장소와 연결할 수 있으며, 예를 들어 main에 푸시할 때 트리거될 수 있습니다.
- Cloud Storage에 애플리케이션 사진을 호스팅합니다. 이는 마운트를 통해 달성되며 앱을 변경하는 데 코드가 필요하지 않습니다.
- Cloud Functions (서버리스)를 통해 오케스트레이션된 Gemini를 통해 생성형 AI 기능 도입
- 새로 업데이트된 앱의 SLO 및 운영을 숙지합니다.
이 단계를 따르면 PHP 애플리케이션을 점진적으로 현대화하여 확장성, 보안, 배포 유연성을 개선할 수 있습니다. 또한 Google Cloud로 이전하면 강력한 인프라와 서비스를 활용하여 클라우드 네이티브 환경에서 애플리케이션이 원활하게 실행되도록 할 수 있습니다.
이 간단한 단계를 따라 학습한 내용은 언어/스택과 사용 사례가 다른 자체 애플리케이션 및 조직에 적용할 수 있습니다.
앱 정보
포크할 애플리케이션 ( MIT 라이선스에 따라 코드)은 MySQL 인증이 있는 기본 PHP 5.7 애플리케이션입니다. 앱의 주요 아이디어는 사용자가 사진을 업로드할 수 있는 플랫폼을 제공하고 관리자가 부적절한 이미지에 태그를 지정할 수 있도록 하는 것입니다. 애플리케이션에는 다음 두 개의 테이블이 있습니다.
- 사용자 관리자와 함께 사전 컴파일됩니다. 신규 사용자가 등록할 수 있습니다.
- Images에 저장 샘플 이미지가 몇 개 포함되어 있습니다. 로그인한 사용자는 새 사진을 업로드할 수 있습니다. 여기에서 마법을 추가합니다.
내 목표
Google Cloud에서 사용할 수 있도록 기존 애플리케이션을 현대화하고 싶습니다. Google은 Cloud SQL, Cloud Run, Cloud Build, Secret Manager 등의 서비스를 사용하여 확장성을 개선하고, 보안을 강화하고, 인프라 관리를 자동화하고, 이미지 처리, 모니터링, 데이터 스토리지와 같은 고급 기능을 통합할 것입니다.
무엇보다도 단계별로 진행하여 각 단계의 사고 과정을 학습할 수 있도록 하고자 합니다. 일반적으로 각 단계는 다음 단계의 새로운 가능성을 열어줍니다 (예: 모듈 2 -> 3, 6 -> 7).
아직 확신이 없으신가요? YouTube에서 7분 길이의 동영상을 확인하세요.
필요한 항목
- 인터넷에 연결되어 있으며 브라우저가 설치되어 있는 컴퓨터
- 일부 GCP 크레딧 자세한 내용은 다음 단계를 참고하세요.
- Cloud Shell을 사용합니다. 필요한 모든 사전 설치된 명령어와 IDE가 함께 제공됩니다.
- GitHub 계정 이 저장소는 자체 Git 저장소로 원본 코드 🧑🏻💻 gdgpescara/app-mod-workshop를 분기하는 데 필요합니다. 자체 CI/CD 파이프라인 (자동 커밋 -> 빌드 -> 배포)을 사용하려면 이 작업이 필요합니다.
샘플 솔루션은 여기에서 확인할 수 있습니다.
- 저자 저장소: https://github.com/Friends-of-Ricc/app-mod-workshop
.solutions/
폴더 아래에 원래 워크숍 저장소(장별)
이 워크숍은 브라우저의 Cloud Shell에서 완료하도록 설계되었습니다.
하지만 로컬 컴퓨터에서도 시도할 수 있습니다.
2. 크레딧 설정 및 포크
GCP 크레딧 사용 및 GCP 환경 설정[선택사항]
이 워크숍을 진행하려면 크레딧이 있는 결제 계정이 필요합니다. 이미 자체 결제가 있는 경우 이 단계를 건너뛸 수 있습니다.
GCP 크레딧에 연결할 새 Google Gmail 계정 (*)을 만듭니다. 강사에게 GCP 크레딧을 사용하기 위한 링크를 요청하거나 bit.ly/PHP-Amarcord-credits에서 크레딧을 사용하세요 .
새로 만든 계정으로 로그인하고 안내를 따릅니다.
(
) 새 Gmail 계정이 필요한 이유는 무엇인가요?*
계정 (특히 직장 또는 학생 이메일)이 이전에 GCP에 노출되어 조직 정책 으로 인해 실습에 실패하는 경우가 있었습니다. 새 Gmail 계정을 만들거나 이전에 GCP를 사용한 적이 없는 기존 Gmail 계정 (gmail.com)을 사용하는 것이 좋습니다.
버튼을 클릭하여 크레딧을 사용합니다.
다음 양식에 이름과 성을 입력하고 이용약관에 동의합니다.
https://console.cloud.google.com/billing에 결제 계정이 표시되기까지 몇 초 정도 기다려야 할 수 있습니다.
완료되면 Google Cloud 콘솔을 열고 왼쪽 상단의 드롭다운 메뉴에서 '조직 없음'이 표시된 프로젝트 선택기를 클릭하여 새 프로젝트를 만듭니다. 아래 참조
아래 스크린샷과 같이 프로젝트가 없으면 새 프로젝트를 만듭니다. 오른쪽 상단에 '새 프로젝트' 옵션이 있습니다.
다음과 같이 새 프로젝트를 GCP 무료 체험 결제 계정에 연결해야 합니다.
이제 Google Cloud Platform을 사용할 수 있습니다. 초보자이거나 클라우드 환경에서 모든 작업을 수행하려는 경우 아래와 같이 왼쪽 상단에 있는 다음 버튼을 통해 Cloud Shell 및 해당 편집기에 액세스할 수 있습니다.
왼쪽 상단에서 새 프로젝트가 선택되어 있는지 확인합니다.
선택되지 않음 (나쁨):
선택됨 (양호):
GitHub에서 앱 포크
- 데모 앱으로 이동합니다(https://github.com/gdgpescara/app-mod-workshop).
- 🍴 포크를 클릭합니다.
- GitHub 계정이 없는 경우 새 계정을 만들어야 합니다.
- 원하는 대로 수정합니다.
- 다음을 사용하여 앱 코드를 클론합니다.
git clone
https://github.com/
YOUR-GITHUB-USER/YOUR-REPO-NAME
- 즐겨 사용하는 편집기로 클론된 프로젝트 폴더를 엽니다. Cloud Shell을 선택한 경우 아래와 같이 '편집기 열기'를 클릭하여 이 작업을 수행할 수 있습니다.
다음 그림과 같이 Google Cloud Shell 편집기를 사용하면 필요한 모든 것을 갖출 수 있습니다.
'폴더 열기'를 클릭하고 폴더(홈 폴더의 app-mod-workshop
)를 선택하여 시각적으로 확인할 수 있습니다.
3. 모듈 1: SQL 인스턴스 만들기
Google Cloud SQL 인스턴스 만들기
PHP 앱이 MySQL 데이터베이스에 연결되므로 원활한 마이그레이션을 위해 Google Cloud에 복제해야 합니다. Cloud SQL은 클라우드에서 완전 관리형 MySQL 데이터베이스를 실행할 수 있으므로 완벽한 선택입니다. 다음 단계를 따르세요.
- Cloud SQL 페이지(https://console.cloud.google.com/sql/instances)로 이동합니다.
- '인스턴스 만들기'를 클릭합니다.
- 필요한 경우 API를 사용 설정합니다. 이 작업은 몇 초 정도 걸릴 수 있습니다.
- MySQL을 선택합니다.
- (가장 저렴한 버전을 제공하여 더 오래 사용할 수 있도록 노력하고 있습니다.)
- 버전: Enterprise
- 사전 설정: 개발 (샌드박스를 사용해 봤지만 효과가 없었습니다.)
- MySQL 버전: 5.7 (과거의 향수를 불러일으키네요.)
- 인스턴스 ID:
appmod-phpapp
를 선택합니다. 이를 변경하는 경우 향후 스크립트와 솔루션도 그에 따라 변경해야 합니다. - 비밀번호: 원하는 대로 입력하되 CLOUDSQL_INSTANCE_PASSWORD로 기록해 둡니다.
- 리전: 앱의 나머지 부분에 선택한 것과 동일하게 유지합니다 (예: 밀라노 =
europe-west8
). - 영역 가용성: 단일 영역 (데모를 위해 비용 절감)
인스턴스 만들기 버튼을 클릭하여 Cloud SQL 데이터베이스를 배포합니다. ⌛ 완료하는 데 약 10분이 걸립니다⌛. 그동안 문서를 계속 읽으세요. 첫 번째 부분(DB 연결을 수정할 때까지)에서는 이 모듈에 종속되지 않으므로 다음 모듈('PHP 앱 컨테이너화')을 시작해도 됩니다.
참고: 이 인스턴스의 비용은 하루에 약 7달러입니다. 워크숍이 끝난 후에는 반드시 분리하세요.
Cloud SQL에서 image_catalog DB 및 사용자 만들기
앱 프로젝트에는 두 개의 SQL 파일이 포함된 db/
폴더가 함께 제공됩니다.
- 01_schema.sql : 사용자 및 이미지 데이터를 포함하는 두 개의 테이블을 만드는 SQL 코드가 포함되어 있습니다.
- 02_seed.sql: 이전에 생성된 테이블에 데이터를 시드하는 SQL 코드가 포함되어 있습니다.
이러한 파일은 나중에 image_catalog
데이터베이스가 생성되면 사용됩니다. 다음 단계를 따라 이 작업을 수행할 수 있습니다.
- 인스턴스를 열고 데이터베이스 탭을 클릭합니다.
- '데이터베이스 만들기'를 클릭합니다.
image_catalog
(PHP 앱 구성에서와 같이)라고 호출합니다.
그런 다음 데이터베이스 사용자를 만듭니다. 이를 통해 image_catalog 데이터베이스로 인증할 수 있습니다.
- 이제 사용자 탭을 클릭합니다.
- '사용자 계정 추가'를 클릭합니다.
- 사용자: 하나 만들어 줘.
- 사용자 이름:
appmod-phpapp-user
- 비밀번호: 기억할 수 있는 비밀번호를 선택하거나 '생성'을 클릭합니다.
- '모든 호스트 허용 (%)'을 유지합니다.
- 추가를 클릭합니다.
잘 알려진 IP에 DB를 엽니다.
Cloud SQL의 모든 DB는 '격리'된 상태로 생성됩니다. 액세스할 수 있는 네트워크를 명시적으로 설정해야 합니다.
- 인스턴스를 클릭합니다.
- '연결' 메뉴를 엽니다.
- '네트워킹' 탭을 클릭합니다.
- '승인된 네트워크'에서 클릭합니다. 이제 네트워크 (즉, 서브넷)를 추가합니다.
- 지금은 앱이 작동하도록 빠르지만 보안이 취약한 설정을 선택하세요. 나중에 신뢰할 수 있는 IP로 제한할 수 있습니다.
- 이름: '전 세계 모든 사용자 - INSECURE'
- 네트워크: '
0.0.0.0/0"
'(참고: 보안되지 않은 부분임) - '완료' 클릭
- 저장을 클릭합니다.
다음과 같은 결과를 확인할 수 있습니다.
참고: 이 솔루션은 O(시간) 내에 워크숍을 완료하기 위한 적절한 절충안입니다. 하지만 보안 문서를 확인하여 프로덕션용 솔루션을 보호하세요.
이제 DB 연결을 테스트해 보세요.
이전에 만든 image_catalog
사용자가 작동하는지 확인해 보겠습니다.
인스턴스 내에서 'Cloud SQL Studio'에 액세스하고 아래와 같이 인증할 데이터베이스, 사용자, 비밀번호를 입력합니다.
이제 SQL 편집기를 열고 다음 섹션으로 진행할 수 있습니다.
코드베이스에서 데이터베이스 가져오기
SQL 편집기를 사용하여 데이터와 함께 image_catalog
테이블을 가져옵니다. 저장소의 파일 ( 01_schema.sql, 02_seed.sql)에서 SQL 코드를 복사하여 순차적으로 실행합니다.
이렇게 하면 아래와 같이 image_catalog에 users와 images라는 두 개의 테이블이 표시됩니다.
편집기에서 select * from images;
을 실행하여 테스트할 수 있습니다.
Cloud SQL 인스턴스의 공개 IP 주소도 기록해 둡니다. 나중에 필요합니다. IP를 확인하려면 개요 페이지의 Cloud SQL 인스턴스 기본 페이지로 이동합니다. (개요 > 이 인스턴스에 연결 > 공개 IP 주소)
4. 모듈 2: PHP 앱 컨테이너화
클라우드용으로 이 앱을 빌드하려고 합니다.
즉, 코드를 클라우드에서 실행하는 데 필요한 모든 정보가 포함된 ZIP 파일로 패키징해야 합니다.
패키징하는 방법은 다음과 같습니다.
- Docker 매우 인기 있지만 올바르게 설정하기가 다소 복잡합니다.
- Buildpacks 인기가 적지만 빌드할 항목과 실행할 항목을 '자동 추측'하는 경향이 있습니다. 대부분의 경우 바로 작동합니다.
이 워크숍에서는 Docker를 사용한다고 가정합니다.
Cloud Shell을 사용하기로 한 경우 지금 다시 엽니다 (Cloud 콘솔의 오른쪽 상단 클릭).
이렇게 하면 페이지 하단에 편리한 셸이 열리며, 여기에서 설정 단계에서 코드를 포크해야 합니다.
Docker
제어 기능을 사용하려면 이 솔루션이 적합합니다. 특정 라이브러리를 구성하고 명확하지 않은 특정 동작 (업로드의 chmod, 앱의 비표준 실행 파일 등)을 삽입해야 하는 경우에 유용합니다.
컨테이너화된 애플리케이션을 Cloud Run에 최종적으로 배포하려면 다음 문서를 확인하세요. PHP 8에서 PHP 5.7로 백포트하려면 어떻게 해야 할까요? Gemini를 사용해 보세요. 또는 미리 빌드된 다음 버전을 사용할 수 있습니다.
# Use the official PHP image: https://hub.docker.com/_/php
FROM php:5.6-apache
# Configure PHP for Cloud Run.
# Precompile PHP code with opcache.
# Install PHP's extension for MySQL
RUN docker-php-ext-install -j "$(nproc)" opcache mysqli pdo pdo_mysql && docker-php-ext-enable pdo_mysql
RUN set -ex; \
{ \
echo "; Cloud Run enforces memory & timeouts"; \
echo "memory_limit = -1"; \
echo "max_execution_time = 0"; \
echo "; File upload at Cloud Run network limit"; \
echo "upload_max_filesize = 32M"; \
echo "post_max_size = 32M"; \
echo "; Configure Opcache for Containers"; \
echo "opcache.enable = On"; \
echo "opcache.validate_timestamps = Off"; \
echo "; Configure Opcache Memory (Application-specific)"; \
echo "opcache.memory_consumption = 32"; \
} > "$PHP_INI_DIR/conf.d/cloud-run.ini"
# Copy in custom code from the host machine.
WORKDIR /var/www/html
COPY . .
# Setup the PORT environment variable in Apache configuration files: https://cloud.google.com/run/docs/reference/container-contract#port
ENV PORT=8080
# Tell Apache to use 8080 instead of 80.
RUN sed -i 's/80/${PORT}/g' /etc/apache2/sites-available/000-default.conf /etc/apache2/ports.conf
# Note: This is quite insecure and opens security breaches. See last chapter for hardening ideas.
# Uncomment at your own risk:
#RUN chmod 777 /var/www/html/uploads/
# Configure PHP for development.
# Switch to the production php.ini for production operations.
# RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
# https://github.com/docker-library/docs/blob/master/php/README.md#configuration
RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
# Expose the port
EXPOSE 8080
최신 Dockerfile
버전은 여기에서 확인할 수 있습니다.
애플리케이션을 로컬에서 테스트하려면 PHP 앱이 Google CloudSQL에서 사용할 수 있는 MySQL DB에 연결되도록 config.php 파일을 변경해야 합니다. 이전에 설정한 내용을 바탕으로 빈칸을 채웁니다.
<?php
// Database configuration
$db_host = '____________';
$db_name = '____________';
$db_user = '____________';
$db_pass = '____________';
try {
$pdo = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("Errore di connessione: " . $e->getMessage());
}
session_start();
?>
DB_HOST
은 Cloud SQL 공개 IP 주소이며 SQL 콘솔에서 확인할 수 있습니다.
DB_NAME
은 변경되지 않아야 합니다.image_catalog
DB_USER
은appmod-phpapp-user
이어야 합니다.DB_PASS
은 내가 선택한 것입니다. 작은따옴표로 설정하고 필요에 따라 이스케이프합니다.
또한 Gemini를 사용하여 몇 개의 🇮🇹 이탈리아어 작품을 영어로 번역하셔도 됩니다.
이제 Dockerfile
가 있고 DB에 연결하도록 PHP 앱을 구성했으므로 이를 사용해 보겠습니다.
아직 Docker가 없는 경우 설치합니다 ( 링크). Cloud Shell을 사용하는 경우 이 단계는 필요하지 않습니다.
이제 적절한 docker 빌드 및 실행 명령어를 사용하여 컨테이너화된 PHP 앱을 빌드하고 실행해 보세요.
# Build command - don't forget the final . This works if Dockerfile is inside the code folder:
$ docker build -t my-php-app-docker .
# Local Run command: most likely ports will be 8080:8080
$ docker run -it -p <CONTAINER_PORT>:<LOCAL_MACHINE_PORT> my-php-app-docker
모든 것이 제대로 작동한다면 로컬 호스트에 연결했을 때 다음 웹페이지가 표시됩니다. 이제 앱이 포트 8080에서 실행됩니다. '웹 미리보기' 아이콘 (눈이 있는 브라우저)을 클릭한 다음 포트 8080에서 미리보기 (또는 다른 포트의 경우 '포트 변경')를 클릭합니다.
브라우저에서 결과 테스트하기
이제 애플리케이션이 다음과 같이 표시됩니다.
Admin/admin123으로 로그인하면 다음과 같이 표시됩니다.
좋습니다. 이탈리아어 텍스트를 제외하고는 작동합니다. 🎉🎉🎉
도커화는 제대로 되었지만 DB 사용자 인증 정보가 잘못된 경우 다음과 같은 결과가 표시될 수 있습니다.
거의 다 왔어요. 다시 시도해 보세요.
Artifact Registry에 저장[선택사항]
이제 클라우드에 배포할 준비가 된 컨테이너화된 PHP 애플리케이션이 있어야 합니다. 다음으로 Docker 이미지를 저장하고 Cloud Run과 같은 Google Cloud 서비스에 배포할 수 있도록 액세스할 수 있는 클라우드 위치가 필요합니다. 이 스토리지 솔루션은 Docker 컨테이너 이미지, Maven 패키지, npm 모듈 등을 비롯한 애플리케이션 아티팩트를 저장하도록 설계된 완전 관리형 Google Cloud 서비스인 Artifact Registry라고 합니다.
적절한 버튼을 사용하여 Google Cloud Artifact Registry에 저장소를 만들어 보겠습니다.
아티팩트를 저장하는 데 적합한 유효한 이름, 형식, 리전을 선택합니다.
로컬 개발 환경으로 돌아가 방금 만든 Artifact Registry 저장소에 앱 컨테이너 이미지를 태그하고 푸시합니다. 다음 명령어를 완료하여 실행합니다.
- docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
- docker push TARGET_IMAGE[:TAG]
결과는 다음 스크린샷과 같아야 합니다.
만세 🎉🎉🎉 다음 단계로 이동할 수 있습니다. 그 전에 2분 정도 시간을 내어 업로드/로그인/로그아웃을 시도하고 앱 엔드포인트를 숙지하세요.나중에 필요합니다.
발생 가능한 오류
컨테이너화 오류가 발생하면 Gemini를 사용하여 오류를 설명하고 수정해 보세요. 다음을 제공합니다.
- 현재 Dockerfile
- 수신된 오류
- [필요한 경우] 실행 중인 PHP 코드
업로드 권한 /upload.php
엔드포인트를 사용해 사진을 업로드해 보세요. 아래와 같은 오류가 표시될 수 있습니다. 이 경우 Dockerfile
에서 chmod/chown
수정 작업을 해야 합니다.
경고: move_uploaded_file(uploads/image (3).png): failed to open stream: Permission denied in /var/www/html/upload.php on line 11
PDOException '드라이버를 찾을 수 없음' (또는 'Errore di connessione: 드라이버를 찾을 수 없음') Dockerfile에 DB에 연결하기 위한 mysql (pdo_mysql
)용 적절한 PDO 라이브러리가 있는지 확인합니다. 여기에서 솔루션에 대한 아이디어를 얻으세요.
요청을 백엔드로 전달할 수 없습니다. 포트 8080의 서버에 연결할 수 없습니다. 이는 잘못된 포트를 노출하고 있음을 의미합니다. Apache/Nginx가 실제로 제공하는 포트를 노출해야 합니다. 이는 사소한 문제가 아닙니다. 가능하다면 포트를 8080으로 설정하세요 (Cloud Run을 더 쉽게 사용할 수 있음). Apache에서 원하는 대로 포트 80을 유지하려면 다른 명령어를 사용하여 실행하세요.
$ docker run -it -p 8080:80 # force 80
# Use the PORT environment variable in Apache configuration files.
# https://cloud.google.com/run/docs/reference/container-contract#port
RUN sed -i 's/80/${PORT}/g' /etc/apache2/sites-available/000-default.conf /etc/apache2/ports.conf
5. 모듈 3: Cloud Run에 앱 배포
Cloud Run을 선택해야 하는 이유
좋은 질문입니다. 몇 년 전이었다면 Google App Engine을 선택했을 것입니다.
간단히 말해 현재 Cloud Run은 최신 기술 스택을 갖추고 있으며, 배포가 더 쉽고, 비용이 저렴하며, 사용하지 않을 때는 0으로 축소됩니다. 상태 비저장 컨테이너를 실행할 수 있는 유연성과 다양한 Google Cloud 서비스와의 통합을 통해 오버헤드를 최소화하고 효율성을 극대화하여 마이크로서비스와 최신 애플리케이션을 배포하는 데 적합합니다.
좀 더 구체적으로 말하면 Cloud Run은 Google Cloud의 완전 관리형 플랫폼으로, 서버리스 환경에서 스테이트리스(Stateless) 컨테이너화된 애플리케이션을 실행할 수 있습니다. 들어오는 트래픽에 맞게 0에서 확장하고 유휴 상태일 때는 축소하여 모든 인프라를 자동으로 처리하므로 비용 효율적이고 효율적입니다. Cloud Run은 컨테이너에 패키지화된 모든 언어 또는 라이브러리를 지원하므로 개발 시 유연성이 뛰어납니다. 다른 Google Cloud 서비스와 잘 통합되며 서버 인프라를 관리할 필요 없이 마이크로서비스, API, 웹사이트, 이벤트 기반 애플리케이션을 빌드하는 데 적합합니다.
기본 요건
이 작업을 완료하려면 로컬 머신에 gcloud
가 설치되어 있어야 합니다. 그렇지 않은 경우 여기에서 안내를 참고하세요. Google Cloud Shell을 사용하는 경우 취해야 할 조치가 없습니다.
배포하기 전에...
로컬 환경에서 작업하는 경우 다음을 사용하여 Google Cloud에 인증합니다.
$ gcloud auth login –update-adc # not needed in Cloud Shell
이렇게 하면 브라우저에서 OAuth 로그인을 통해 인증됩니다. 결제가 사용 설정된 Google Cloud에 로그인한 사용자와 동일한 사용자 (예: vattelapesca@gmail.com)로 Chrome을 통해 로그인해야 합니다.
다음 명령어를 사용하여 Cloud Run API를 사용 설정합니다.
$ gcloud services enable run.googleapis.com cloudbuild.googleapis.com
이제 Cloud Run에 배포할 준비가 되었습니다.
gcloud를 통해 Cloud Run에 앱 배포
Cloud Run에 앱을 배포할 수 있는 명령어는 gcloud run deploy
입니다. 목표를 달성하기 위해 설정할 수 있는 옵션은 여러 가지가 있습니다. 최소 옵션 세트 (명령줄을 통해 제공하거나 도구에서 대화형 프롬프트로 요청할 수 있음)는 다음과 같습니다.
- 앱에 배포할 Cloud Run 서비스의 이름입니다. Cloud Run 서비스는 앱의 엔드포인트를 제공하는 URL을 반환합니다.
- 앱이 실행될 Google Cloud 리전입니다. (
--region
지역) - 앱을 래핑하는 컨테이너 이미지
- 앱이 실행 중에 사용해야 하는 환경 변수입니다.
- 추가 인증 없이 모든 사용자가 앱에 액세스할 수 있도록 허용하는 Allow-Unauthenticated 플래그
문서를 참고하여 이 옵션을 명령줄에 적용하는 방법을 알아보세요. 아래로 스크롤하여 해결 방법을 확인할 수도 있습니다.
배포하는 데 몇 분 정도 걸립니다. 모든 항목이 올바르면 Google Cloud 콘솔에 다음과 같이 표시됩니다.
Cloud Run에서 제공하는 URL을 클릭하고 애플리케이션을 테스트합니다. 인증되면 다음과 같이 표시됩니다.
인수 없이 'gcloud run deploy' 실행
gcloud run deploy
가 적절한 질문을 하고 사용자가 남긴 빈칸을 채우는 것을 알 수 있습니다. 정말 멋져요.
하지만 몇몇 모듈에서는 이 명령어를 Cloud Build 트리거에 추가할 예정이므로 대화형 질문을 사용할 수 없습니다. 명령어의 모든 옵션을 입력해야 합니다. 따라서 황금 gcloud run deploy --option1 blah --foo bar --region your-fav-region
을 만들어야 합니다. 어떻게 하시나요?
- gcloud에서 질문을 중지할 때까지 2~3~4단계를 반복합니다.
- [LOOP] 지금까지 찾은 옵션이 포함된
gcloud run deploy
- [LOOP] 시스템에서 옵션 X를 요청함
- [LOOP] 공개 문서에서 CLI에서 X를 설정하는 방법을 검색하고
--my-option [my-value]
옵션을 추가합니다. - gcloud가 추가 질문 없이 완료되지 않는 한 이제 2단계로 돌아갑니다.
- 이 gcloud run deploy BLAH BLAH BLAH는 정말 최고야! 나중에 Cloud Build 단계에서 필요하므로 명령어를 저장해 둡니다.
가능한 해결 방법은 여기를 참고하세요. 문서는 여기에 있습니다.
축하합니다 🎉🎉🎉 Google Cloud에 앱을 배포하여 현대화의 첫 번째 단계를 완료했습니다.
6. 모듈 4: Secret Manager를 사용한 비밀번호 정리
이전 단계에서 Cloud Run에 앱을 배포하고 실행할 수 있었습니다. 하지만 일부 보안 비밀을 일반 텍스트로 제공하는 보안 권장사항을 따르지 않았습니다.
첫 번째 반복: ENV를 사용하도록 config.php 업데이트
config.php 파일의 코드에 DB 비밀번호를 바로 입력한 것을 알 수 있습니다. 이는 테스트 목적으로 앱이 작동하는지 확인하는 데 적합합니다. 하지만 프로덕션 환경에서와 같이 코드를 커밋/사용할 수는 없습니다. 비밀번호 (및 기타 DB 연결 매개변수)는 동적으로 읽어 런타임에 앱에 제공해야 합니다. ENV 변수에서 db 매개변수를 읽도록 config.php 파일을 변경합니다. 실패하는 경우 기본값을 설정하는 것이 좋습니다. ENV 로드에 실패하는 경우에 유용하므로 페이지 출력에서 기본값을 사용하는지 알려줍니다. 빈칸을 채우고 config.php의 코드를 바꿉니다.
<?php
// Database configuration with ENV variables. Set default values as well
$db_host = getenv('DB_HOST') ?: 'localhost';
$db_name = getenv('DB_NAME') ?: 'image_catalog';
$db_user = getenv('DB_USER') ?: 'appmod-phpapp-user';
$db_pass = getenv('DB_PASS') ?: 'wrong_password';
// Note getenv() is PHP 5.3 compatible
try {
$pdo = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("Errore di connessione: " . $e->getMessage());
}
session_start();
?>
앱이 컨테이너화되어 있으므로 앱에 ENV 변수를 제공하는 방법을 제공해야 합니다. 이는 다음과 같은 몇 가지 방법으로 할 수 있습니다.
- 빌드 시 Dockerfile에서 이전 Dockerfile에 ENV DB_VAR=ENV_VAR_VALUE 구문을 사용하여 4개의 매개변수를 추가합니다. 이렇게 하면 런타임에 재정의할 수 있는 기본값이 설정됩니다. 예를 들어 'DB_NAME'과 'DB_USER'는 여기에서만 설정할 수 있습니다.
- 실행 시 CLI 또는 UI에서 Cloud Run의 이러한 변수를 설정할 수 있습니다. Dockerfile에 설정된 기본값을 유지하지 않으려면 여기에 4개의 변수를 모두 넣는 것이 좋습니다.
로컬 호스트에서는 ENV 변수를 .env
파일에 넣는 것이 좋습니다 (solutions 폴더 확인).
또한 .env가 .gitignore
에 추가되었는지 확인하세요. 보안 비밀을 GitHub에 푸시하면 안 됩니다.
echo .env >> .gitignore
그런 다음 로컬에서 인스턴스를 테스트할 수 있습니다.
docker run -it -p 8080:8080 --env-file .env my-php-app-docker
이제 다음을 달성했습니다.
- 앱이 ENV에서 변수를 동적으로 읽습니다.
- 코드에서 DB 비밀번호를 삭제하여 보안이 개선되었습니다.
이제 Cloud Run에 새 버전을 배포할 수 있습니다. UI로 이동하여 환경 변수를 수동으로 설정해 보겠습니다.
- https://console.cloud.google.com/run으로 이동합니다.
- 앱을 클릭합니다.
- '새 버전 수정 및 배포'를 클릭합니다.
- 첫 번째 탭 '컨테이너'에서 하단 탭 '변수 및 보안 비밀'을 클릭합니다.
- '+ 변수 추가'를 클릭하고 필요한 변수를 모두 추가합니다. 다음과 같은 결과가 표시됩니다.
완벽한가요? 아니요. PASS는 대부분의 운영자에게 계속 표시됩니다. 이 문제는 Google Cloud Secret Manager를 사용하여 완화할 수 있습니다.
두 번째 반복: Secret Manager
비밀번호가 자체 코드에서 사라졌습니다. 하지만 아직 안전한가요?
Google Cloud 콘솔에 액세스할 수 있는 사용자는 여전히 비밀번호를 볼 수 있습니다. 실제로 Cloud Run YAML 배포 파일에 액세스하면 검색할 수 있습니다. 또는 새 Cloud Run 버전을 수정하거나 배포하려고 하면 아래 스크린샷에 표시된 것처럼 변수 및 보안 비밀 섹션에 비밀번호가 표시됩니다.
Google Cloud Secret Manager는 API 키, 비밀번호, 인증서, 기타 보안 비밀과 같은 민감한 정보를 관리하는 안전한 중앙 집중식 서비스입니다.
이를 통해 세분화된 권한과 강력한 암호화로 보안 비밀을 저장, 관리, 액세스할 수 있습니다. Google Cloud의 Identity and Access Management (IAM)와 통합된 Secret Manager를 사용하면 특정 비밀에 액세스할 수 있는 사용자를 제어하여 데이터 보안과 규정 준수를 보장할 수 있습니다.
또한 자동 보안 비밀 순환 및 버전 관리를 지원하여 Google Cloud 서비스 전반에서 보안 비밀 수명 주기 관리를 간소화하고 애플리케이션의 보안을 강화합니다.
Secret Manager에 액세스하려면 햄버거 메뉴에서 보안 서비스로 이동하여 아래 스크린샷과 같이 데이터 보호 섹션에서 찾습니다.
다음 이미지에 따라 Secret Manager API를 사용 설정합니다.
- 이제 '보안 비밀 만들기'를 클릭합니다.
- 이름:
php-amarcord-db-pass
- 보안 비밀 값: 'DB 비밀번호'('파일 업로드' 부분은 무시).
- 이 보안 비밀 링크에 주석을 추가합니다.
projects/123456789012/secrets/php-amarcord-db-pass
와 같이 표시됩니다. 보안 비밀에 대한 고유 포인터입니다 (Terraform, Cloud Run 등). 이 번호는 고유한 프로젝트 번호입니다.
도움말: 왼쪽에서 오른쪽으로 전문화되는 방식으로 시크릿에 일관된 이름 지정 규칙을 사용해 보세요(예: cloud-devrel-phpamarcord-dbpass
).
- 조직 (회사)
- 팀 (조직 내)
- 애플리케이션 (팀 내)
- 변수 이름 (앱 내)
이렇게 하면 단일 앱의 모든 비밀을 쉽게 찾을 수 있는 정규식을 사용할 수 있습니다.
새 Cloud Run 버전 만들기
이제 새 보안 비밀이 있으므로 DB_PASS ENV 변수를 삭제하고 새 보안 비밀로 대체해야 합니다. 따라서
- Google Cloud 콘솔을 사용하여 Cloud Run에 액세스
- 앱을 선택합니다.
- '새 버전 수정 및 배포'를 클릭합니다.
- '변수 및 보안 비밀' 탭을 찾습니다.
- '+ 보안 비밀 참조' 버튼을 사용하여 DB_PASS ENV 변수를 재설정합니다.
- 참조된 보안 비밀에 동일한 'DB_PASS'를 사용하고 최신 버전을 사용합니다.
완료되면 다음 오류가 표시됩니다.
해결 방법을 찾아보세요. 이 문제를 해결하려면 IAM 및 관리자 섹션에 액세스하여 권한 부여를 변경해야 합니다. 즐겁게 디버깅하세요!
문제를 파악한 후 Cloud Run으로 돌아가 새 버전을 다시 배포합니다. 결과는 다음 그림과 같이 표시됩니다.
도움말: 개발자 콘솔 (UI)은 권한 문제를 지적하는 데 유용합니다. 시간을 내어 Cloud 엔티티의 모든 링크를 탐색하세요.
7. 모듈 5: Cloud Build로 CI/CD 설정
CI/CD 파이프라인이 필요한 이유
지금까지 gcloud run deploy
을 여러 번 입력했을 것입니다. 같은 질문에 계속해서 답변했을 수도 있습니다.
gcloud run deploy로 앱을 수동으로 배포하는 것이 지겨우신가요? Git 저장소에 새 변경사항을 푸시할 때마다 앱이 자동으로 배포되면 좋지 않나요?
CI/CD 파이프라인을 사용하려면 다음 두 가지가 필요합니다.
- 개인 Git 저장소: 다행히 2단계에서 워크숍 저장소를 GitHub 계정으로 포크했을 것입니다. 그렇지 않으면 뒤로 돌아가서 해당 단계를 완료합니다. 포크된 저장소는 다음과 같이 표시됩니다.
https://github.com/<YOUR_GITHUB_USER>/app-mod-workshop
- Cloud Build. 이 놀랍고 저렴한 서비스를 사용하면 Terraform, 도커화된 앱 등 거의 모든 항목에 대한 빌드 자동화를 구성할 수 있습니다.
이 섹션에서는 Cloud Build 설정에 중점을 둡니다.
Cloud Build를 사용해 보세요.
Cloud Build를 사용하여 다음 작업을 수행합니다.
- Dockerfile을 사용하여 소스를 빌드합니다. 이를 빌드하고 실행하는 데 필요한 모든 항목('빌드 아티팩트')이 포함된 '큰 .zip 파일'이라고 생각하면 됩니다.
- 이 아티팩트를 Artifact Registry (AR)로 푸시합니다.
- 그런 다음 AR에서 Cloud Run으로 앱 'php-amarcord'를 배포합니다.
- 이렇게 하면 기존 앱의 새 버전 ('버전')이 생성되고 (새 코드가 포함된 레이어라고 생각하면 됨) 푸시가 성공하면 트래픽이 새 버전으로 전환되도록 구성됩니다.
다음은 내 php-amarcord
앱의 일부 빌드 예시입니다.
이 모든 것을 어떻게 할 수 있을까요?
- 완벽한 YAML 파일 하나를 작성합니다.
cloudbuild.yaml
- Cloud Build 트리거를 만듭니다.
- Cloud Build UI를 통해 GitHub 저장소에 연결
트리거 만들기 (및 저장소 연결)
- https://console.cloud.google.com/cloud-build/triggers로 이동합니다.
- '트리거 만들기'를 클릭합니다.
- 컴파일:
- 이름:
on-git-commit-build-php-app
와 같이 의미 있는 이름 - 이벤트: 브랜치에 푸시
- 소스: '새 저장소 연결'
- 그러면 오른쪽에 '저장소 연결' 창이 열립니다.
- 소스 제공업체: 'GitHub' (첫 번째)
- '계속'
- 인증을 통해 교차 인증을 위한 GitHub 창이 열립니다. 흐름을 따르고 인내심을 가지세요. 저장소가 많으면 시간이 걸릴 수 있습니다.
- 'Select repo' 계정/저장소를 선택하고 'I understand...' 부분을 체크합니다.
- 오류가 표시되는 경우: 저장소에 GitHub 앱이 설치되지 않았습니다. 'Google Cloud Build 설치'를 클릭하고 안내를 따르세요.
연결을 클릭합니다.
- 빙고! 이제 저장소가 연결되었습니다.
- 트리거 부분으로 돌아가 보겠습니다.
- 구성: 자동 감지됨 (*)
- 고급: 서비스 계정 '[PROJECT_NUMBER]- compute@developer.gserviceaccount.com'을 선택합니다.
- xxxxx는 프로젝트 ID입니다.
- 기본 Compute 서비스 계정은 실습 접근 방식에 적합합니다. 프로덕션에서는 사용하지 마세요. ( 자세히 알아보기)
- 다른 모든 것은 그대로 둡니다.
- '만들기' 버튼을 클릭합니다.
(*) Dockerfile 또는 cloudbuild.yaml을 확인하므로 가장 간단한 방법입니다. 하지만 cloudbuild.yaml
를 사용하면 각 단계에서 수행할 작업을 결정할 수 있습니다.
전원이 공급되고 있어!
이제 Cloud Build 서비스 계정 (서비스 계정이란 무엇인가요?)에 작업을 위해 나를 대신하여 행동하는 '로봇'의 이메일입니다(이 경우 클라우드에서 빌드).
SA가 빌드 및 배포할 수 있도록 권한을 부여하지 않으면 SA가 빌드 및 배포에 실패합니다. 다행히도 간단합니다.
- 'Cloud Build' > ' 설정'으로 이동합니다.
- '[PROJECT_NUMBER]- compute@developer.gserviceaccount.com' 서비스 계정
- 다음 체크박스를 선택합니다.
- Cloud Run
- Secret Manager
- 서비스 계정
- Cloud Build
- '선호하는 서비스 계정으로 설정'도 선택합니다.
Cloud Build YAML은 어디에 있나요?
시간을 내어 자체 클라우드 빌드 YAML을 만드는 것이 좋습니다.
하지만 시간이 없거나 시간을 내고 싶지 않다면 이 솔루션 폴더(.solutions)에서 아이디어를 얻을 수 있습니다.
이제 GitHub에 변경사항을 푸시하고 Cloud Build가 해당 부분을 처리하는 것을 확인할 수 있습니다.
Cloud Build를 설정하는 것은 까다로울 수 있습니다. 다음 날짜까지 몇 차례의 의견 교환이 있을 수 있습니다.
- https://console.cloud.google.com/cloud-build/builds;region=global에서 로그를 확인합니다.
- 오류를 찾는 중입니다.
- 코드에서 수정하고 git commit / git push를 다시 실행합니다.
- 오류가 코드에 있는 것이 아니라 구성에 있는 경우도 있습니다. 이 경우 UI (Cloud Build > '트리거' > 실행)에서 새 빌드를 실행할 수 있습니다.
이 솔루션을 사용하는 경우에도 아직 해야 할 작업이 있습니다. 예를 들어 새로 생성된 개발/프로덕션 엔드포인트의 ENV 변수를 설정해야 합니다.
여기에는 두 가지 방법이 있습니다.
- UI를 통해 - ENV 변수를 다시 설정
- CLI를 통해 나에게 '완벽한' 스크립트를 작성합니다. 예시는 gcloud-run-deploy.sh에서 확인할 수 있습니다 . 엔드포인트와 프로젝트 번호 등 몇 가지를 조정해야 합니다. 프로젝트 번호는 Cloud 개요에서 확인할 수 있습니다.
GitHub에 코드를 커밋하려면 어떻게 해야 하나요?
이 워크숍에서는 git push
에 대한 최적의 방법을 다루지 않습니다. 하지만 막혀서 Cloud Shell에 있는 경우 다음 두 가지 방법이 있습니다.
- CLI를 사용합니다. 로컬로 SSH 키를 추가하고 git@github.com:YOUR_USER/app-mod-workshop.git (http 대신)을 사용하여 원격을 추가합니다.
- VSCode Cloud Shell 편집기를 사용하는 경우 소스 제어 (ctrl-shift-G) 탭을 사용하여 '변경사항 동기화'를 클릭하고 안내를 따릅니다. GitHub 계정을 VS Code에 인증할 수 있으며, 여기에서 풀/푸시가 간편해집니다.
다른 파일 사이에 git add clodubuild.yaml
를 포함해야 합니다. 그렇지 않으면 작동하지 않습니다.
'개발/프로덕션 패리티' 심층 vs. 피상적 [선택사항]
여기에서 모델 버전을 복사한 경우 동일한 DEV 및 PROD 버전이 두 개 있게 됩니다. 이는 Twelve-Factor App의 규칙 10에 부합하는 멋진 기능입니다.
하지만 앱이 동일한 데이터베이스를 가리키도록 두 개의 서로 다른 웹 엔드포인트를 사용하고 있습니다. 워크숍에서는 이 정도면 충분하지만 실제로는 적절한 프로덕션 환경을 만드는 데 시간을 할애해야 합니다. 즉, 개발용 데이터베이스와 프로덕션용 데이터베이스를 각각 하나씩 보유하고 재해 복구 / 고가용성을 위해 데이터베이스를 어디에 둘지 선택해야 합니다. 이 내용은 이 워크숍의 범위를 벗어나지만 생각해 볼 만한 내용입니다.
'심층' 버전의 프로덕션을 진행할 시간이 있다면 다음과 같이 복제해야 하는 모든 리소스를 염두에 두세요.
- Cloud SQL 데이터베이스 (및 SQL 인스턴스)
- GCS 버킷
- Cloud 함수
- 개발 시에는 Gemini 1.5 Flash (저렴하고 빠름)를 모델로 사용하고 Gemini 1.5 Pro (더 강력함)를 사용할 수 있습니다.
일반적으로 앱에 관해 어떤 작업을 할 때마다 프로덕션에 동일한 값이 있어야 하는지 비판적으로 생각해 보세요. 그렇지 않다면 중복된 노력을 기울이게 됩니다. 물론 Terraform을 사용하면 리소스에 환경 (-dev, -prod)을 접미사로 삽입할 수 있으므로 훨씬 쉽습니다.
8. 모듈 6: Google Cloud Storage로 이동
스토리지
현재 앱은 상태를 Docker 컨테이너에 저장합니다. 머신이 고장나거나 앱이 비정상 종료되거나 단순히 새 버전을 푸시하면 새 버전이 예약되고 새 빈 저장소가 제공됩니다. 🙈
이 문제를 해결하는 방법에는 여러 가지가 있습니다.
- DB에 이미지를 저장합니다. 이전 PHP 앱에서 이렇게 했습니다. 복잡성을 더하지 않으므로 가장 간단한 솔루션입니다. 하지만 DB에 지연 시간과 부하가 추가됩니다.
- Cloud Run 앱을 스토리지 친화적인 솔루션(GCE + 영구 디스크)으로 마이그레이션하세요. GKE + 스토리지가 적합할 수도 있습니다. 참고: 제어력을 얻는 대신 민첩성을 잃게 됩니다.
- GCS로 이동합니다. Google Cloud Storage는 전체 Google Cloud에 동급 최고의 스토리지를 제공하며 가장 클라우드에 적합한 솔루션입니다. 하지만 PHP 라이브러리를 사용해야 합니다. GCS용 PHP 5.7 라이브러리가 있나요?
PHP 5.7
가Composer
를 지원하나요? Composer에서 지원하는 가장 오래된 버전은 PHP 5.3.2인 것 같습니다. - Docker 사이드카를 사용해 보세요.
- 또는 GCS Cloud Run 볼륨 마운트를 사용할 수 있습니다. 정말 멋지네요.
🤔 스토리지 마이그레이션 (열린 질문)
[개방형] 이 연습에서는 이미지를 어떤 방식으로든 유지되는 방식으로 이동하는 솔루션을 찾아야 합니다.
수락 테스트
해결 방법을 알려드리고 싶지는 않지만 다음과 같은 상황이 발생하기를 바랍니다.
newpic.jpg
를 업로드합니다. 앱에서 확인할 수 있습니다.- 앱을 새 버전으로 업그레이드합니다.
newpic.jpg
이 여전히 표시됩니다.
💡 가능한 해결 방법 (GCS Cloud Run 볼륨 마운트)
이는 코드를 전혀 건드리지 않고 (이미지 설명을 표시하는 것은 제외, 이는 사소하고 눈을 즐겁게 하기 위한 것임) 상태 저장 파일 업로드를 달성할 수 있는 매우 우아한 솔루션입니다.
이렇게 하면 Cloud Run에서 GCS로 폴더를 마운트할 수 있습니다.
- GCS에 업로드된 모든 항목이 앱에 실제로 표시됩니다.
- 앱에 대한 모든 업로드는 실제로 GCS에 업로드됩니다.
- GCS에 업로드된 객체에 마법이 적용됩니다 (7장).
참고: FUSE 세부사항을 읽어보세요. 성능이 문제인 경우 이는 허용되지 않습니다.
GCS 버킷 만들기
GCS는 Google Cloud의 어디에나 있는 스토리지 서비스입니다. 스토리지에 필요한 모든 GCP 서비스에서 사용되며, 실전에서 검증되었습니다.
Cloud Shell은 PROJECT_ID를 GOOGLE_CLOUD_PROJECT로 내보냅니다.
$ export PROJECT_ID=$GOOGLE_CLOUD_PROJECT
#!/bin/bash
set -euo pipefail
# Your Cloud Run Service Name, eg php-amarcord-dev
SERVICE_NAME='php-amarcord-dev'
BUCKET="${PROJECT_ID}-public-images"
GS_BUCKET="gs://${BUCKET}"
# Create bucket
gsutil mb -l "$GCP_REGION" -p "$PROJECT_ID" "$GS_BUCKET/"
# Copy original pictures there - better if you add an image of YOURS before.
gsutil cp ./uploads/*.png "$GS_BUCKET/"
/uploads/ 폴더에 버킷을 마운트하도록 Cloud Run 구성
이제 우아한 부분을 살펴보겠습니다. 볼륨 php_uploads
를 만들고 Cloud Run에 MOUNT_PATH
에서 FUSE 마운트를 실행하도록 지시합니다 (예: /var/www/html/uploads/
).
#!/bin/bash
set -euo pipefail
# .. keep variables from previous script..
# Uploads folder within your docker container.
# Tweak it for your app code.
MOUNT_PATH='/var/www/html/uploads/'
# Inject a volume mount to your GCS bucket in the right folder.
gcloud --project "$PROJECT_ID" beta run services update "$SERVICE_NAME" \
--region $GCP_REGION \
--execution-environment gen2 \
--add-volume=name=php_uploads,type=cloud-storage,bucket="$BUCKET" \
--add-volume-mount=volume=php_uploads,mount-path="$MOUNT_PATH"
이제 Cloud Storage를 가리키려는 모든 엔드포인트에 대해 이 단계를 반복합니다.
UI에서도 동일한 작업을 수행할 수 있습니다.
- '볼륨' 탭에서 버킷을 가리키는 볼륨 마운트를 만듭니다. 유형은 'Cloud Storage 버킷'이며 이름은 'php_uploads'입니다.
- 컨테이너 > 볼륨 마운트에서 앱이 요청한 볼륨 지점에 방금 만든 볼륨을 마운트합니다. 이는 Dockerfile에 따라 다르지만
var/www/html/uploads/
와 비슷할 수 있습니다 .
어떤 방법을 사용하든 작동한다면 새 Cloud Run 버전을 수정할 때 다음과 같이 표시됩니다.
이제 /upload.php
엔드포인트에 새 이미지를 하나 업로드하여 새 애플리케이션을 테스트합니다.
PHP 코드를 한 줄도 작성하지 않고 이미지가 GCS에서 원활하게 흐릅니다.
무슨 일이 일어난 거지?
매우 마법 같은 일이 일어났습니다.
오래된 코드가 포함된 이전 애플리케이션은 여전히 작동합니다. 새로운 최신 스택을 사용하면 앱의 모든 이미지/사진이 상태 저장 Cloud 버킷에 편안하게 저장됩니다. 이제 다음과 같은 무한한 가능성을 누릴 수 있습니다.
- '위험' 또는 '과도한 노출'이 포함된 이미지가 수신될 때마다 이메일을 보내고 싶으신가요? PHP 코드를 수정하지 않고도 이 작업을 할 수 있습니다.
- 이미지가 들어올 때마다 Gemini 멀티모달 모델을 사용하여 이미지를 설명하고 설명과 함께 DB를 업로드하고 싶으신가요? PHP 코드를 수정하지 않고도 이 작업을 할 수 있습니다. 못 믿겠어? 7장에서 계속 읽어보세요.
여기에서 큰 기회를 포착했습니다.
9. 모듈 7: Google Gemini로 앱 강화하기
이제 클라우드화된 스토리지가 있는 멋지고 최신식의 새로운 PHP 앱 (2024년형 Fiat 126
와 같음)이 있습니다.
필드로 할 수 있는 작업
기본 요건
이전 장에서는 모델 솔루션을 통해 GCS에 이미지 /uploads/
를 마운트하여 앱 로직과 이미지 저장소를 사실상 분리할 수 있었습니다.
이 연습에서는 다음을 수행해야 합니다.
- 6장 (스토리지)의 연습을 성공적으로 완료했습니다.
- 사용자가 앱에 사진을 업로드하고 사진이 버킷으로 흐르는 이미지 업로드가 있는 GCS 버킷이 있습니다.
Cloud 함수 설정 (Python)
이벤트 기반 애플리케이션을 구현하는 방법을 궁금해한 적이 있나요? 다음과 같은 내용이 표시됩니다.
- <event>가 발생하면 이메일을 보냅니다.
- <event>가 발생하면 => <condition>이 참이면 데이터베이스를 업데이트합니다.
이벤트는 BigQuery에서 사용할 수 있는 새 레코드, GCS의 폴더에서 변경된 새 객체, Pub/Sub의 대기열에서 대기 중인 새 메시지 등 다양합니다.
Google Cloud는 이를 달성하기 위해 여러 패러다임을 지원합니다. 특히 다음 항목에 주의해야 합니다.
- EventArc GCS 이벤트를 수신하는 방법을 확인하세요. 클라우드에서 if-then-else를 기반으로 DAG를 만들고 작업을 오케스트레이션하는 데 유용합니다.
- Cloud Scheduler 예를 들어 Cloud에서 자정 cron 작업에 적합합니다.
- Cloud Workflows Event Arc와 마찬가지로
- Cloud Run Functions (
lambdas
로도 알려져 있음) - Cloud Composer. 기본적으로 Google 버전의 Apache Airflow이며 DAG에도 적합합니다.
이 연습에서는 Cloud 함수를 자세히 살펴보고 꽤 멋진 결과를 얻어 보겠습니다. 선택사항인 연습 문제도 제공됩니다.
샘플 코드는 .solutions/
에서 제공됩니다.
Cloud 함수 설정 (🐍 Python)
Google은 매우 야심찬 GCF를 만들려고 노력하고 있습니다.
- GCS에 새 이미지가 생성되는 경우 (아마도 누군가 앱에 업로드했기 때문일 것입니다. 하지만 이것이 전부는 아닙니다.)
- .. Gemini를 호출하여 설명하고 이미지의 텍스트 설명을 가져옵니다 .. (MIME을 확인하여 PDF, MP3 또는 텍스트가 아닌 이미지인지 확인하는 것이 좋습니다.)
- .. and update the DB with this description. (
images
테이블에description
열을 추가하려면 DB에 패치를 적용해야 할 수 있음)
DB를 패치하여 description
to images 추가
- Cloud SQL Studio를 엽니다.
- 이미지 DB의 사용자 및 비밀번호를 입력합니다.
- 이미지 설명을 위한 열을 추가하는 다음 SQL을 삽입합니다.
ALTER TABLE images ADD COLUMN description TEXT;
빙고! 지금 작동하는지 확인해 보세요.
SELECT * FROM images;
새 설명 열이 표시됩니다.
Gemini f(x) 작성
참고: 이 함수는 실제로 Gemini Code Assist의 도움을 받아 생성되었습니다.
참고: 이 함수를 만들면 IAM 권한 오류가 발생할 수 있습니다. 일부는 아래의 '가능한 오류' 단락에 설명되어 있습니다.
- API 사용 설정
- https://console.cloud.google.com/functions/list로 이동합니다.
- '함수 만들기'를 클릭합니다.
- API 마법사에서 API를 사용 설정합니다.
UI 또는 명령줄에서 GCF를 만들 수 있습니다. 여기서는 명령줄을 사용합니다.
가능한 코드는 .solutions/
에서 확인할 수 있습니다.
- 코드를 호스팅할 폴더를 만듭니다(예: 'gcf/'). 폴더로 이동합니다.
requirements.txt
파일을 만듭니다.
google-cloud-storage
google-cloud-aiplatform
pymysql
- Python 함수를 만듭니다. 샘플 코드는 gcf/main.py를 참고하세요.
#!/usr/bin/env python
"""Complete this"""
from google.cloud import storage
from google.cloud import aiplatform
import vertexai
from vertexai.generative_models import GenerativeModel, Part
import os
import pymysql
import pymysql.cursors
# Replace with your project ID
PROJECT_ID = "your-project-id"
GEMINI_MODEL = "gemini-1.5-pro-002"
DEFAULT_PROMPT = "Generate a caption for this image: "
def gemini_describe_image_from_gcs(gcs_url, image_prompt=DEFAULT_PROMPT):
pass
def update_db_with_description(image_filename, caption, db_user, db_pass, db_host, db_name):
pass
def generate_caption(event, context):
"""
Cloud Function triggered by a GCS event.
Args:
event (dict): The dictionary with data specific to this type of event.
context (google.cloud.functions.Context): The context parameter contains
event metadata such as event ID
and timestamp.
"""
pass
- 함수를 푸시합니다. gcf/push-to-gcf.sh와 비슷한 스크립트를 사용할 수 있습니다.
참고 1. 올바른 값으로 ENV를 소싱하거나 상단에 추가해야 합니다 (GS_BUCKET=blah
등).
참고 2. 이렇게 하면 모든 로컬 코드 (.
)가 푸시되므로 특정 폴더에 코드를 둘러싸고 .gcloudignore
를 전문가처럼 사용하여 대규모 라이브러리가 푸시되지 않도록 하세요. ( 예)
#!/bin/bash
set -euo pipefail
# add your logic here, for instance:
source .env || exit 2
echo "Pushing ☁️ f(x)☁ to 🪣 $GS_BUCKET, along with DB config.. (DB_PASS=$DB_PASS)"
gcloud --project "$PROJECT_ID" functions deploy php_amarcord_generate_caption \
--runtime python310 \
--region "$GCP_REGION" \
--trigger-event google.cloud.storage.object.v1.finalized \
--trigger-resource "$BUCKET" \
--set-env-vars "DB_HOST=$DB_HOST,DB_NAME=$DB_NAME,DB_PASS=$DB_PASS,DB_USER=$DB_USER" \
--source . \
--entry-point generate_caption \
--gen2
참고: 이 예에서 generate_caption
은 호출된 메서드이며 Cloud Function은 모든 관련 정보 (버킷 이름, 객체 이름 등)와 함께 GCS 이벤트를 전달합니다. 시간을 내어 해당 이벤트 Python 사전을 디버그하세요.
함수 테스트
단위 테스트
이 함수에는 작동하는 부분이 많이 있습니다. 모든 단일 항목을 테스트할 수 있습니다.
예는 gcf/test.py에 있습니다.
Cloud Functions UI
또한 UI에서 함수를 살펴보세요. 모든 탭을 살펴볼 가치가 있지만 특히 Source
(가장 좋아하는 탭), Variables
, Trigger
, Logs
탭을 살펴보세요. Logs
에서 오류를 해결하는 데 많은 시간을 할애하게 될 것입니다 (이 페이지 하단의 가능한 오류도 참고). Permissions
도 확인하세요.
E2E 테스트
이제 함수를 수동으로 테스트할 시간입니다.
- 앱으로 이동하여 로그인합니다.
- 사진을 업로드합니다 (너무 크지 않아야 합니다. 큰 이미지에 문제가 있는 것으로 확인됨).
- UI에서 사진이 업로드되었는지 확인합니다.
- Cloud SQL Studio에서 설명이 업데이트되었는지 확인합니다. 로그인하고
SELECT * FROM images
쿼리를 실행합니다.
그리고 효과도 뛰어납니다. 프런트엔드를 업데이트하여 해당 설명을 표시할 수도 있습니다.
PHP를 업데이트하여 [선택사항]표시
앱이 작동하는 것으로 확인되었습니다. 하지만 사용자도 이 설명을 볼 수 있으면 좋겠습니다.
index.php
에 설명을 추가하기 위해 PHP 전문가가 될 필요는 없습니다. 이 코드는 다음 작업을 실행합니다 (Gemini가 작성했습니다).
<?php if (!empty($image['description'])): ?>
<p class="font-bold">Gemini Caption:</p>
<p class="italic"><?php echo $image['description']; ?></p>
<?php endif; ?>
이 코드를 foreach
내에 원하는 대로 배치합니다.
다음 단계에서는 Gemini Code Assist 덕분에 더 예쁜 UI 버전도 확인할 수 있습니다. 예쁜 버전은 다음과 같습니다.
결론
GCS에 새 객체가 도착하면 트리거되는 Cloud Functions를 사용하여 사람이 할 수 있는 것처럼 이미지 콘텐츠에 주석을 달고 DB를 자동으로 업데이트할 수 있습니다. 와우!
다음 단계 동일한 추론을 따라 두 가지 유용한 기능을 구현할 수 있습니다.
[선택사항] 추가 Cloud Functions [개방형]
몇 가지 추가 기능이 떠오릅니다.
📩 이메일 트리거
누군가 사진을 보낼 때마다 이메일을 보내는 이메일 트리거
- 너무 자주? 추가 제약 조건: 큰 이미지 또는 Gemini 콘텐츠에 '과도한 노출/폭력'이라는 단어가 포함된 이미지
EventArc
에서 확인해 보세요.
🚫 부적절한 사진 자동 관리
현재는 사람이 관리자가 '부적절'한 이미지를 신고하고 있습니다. Gemini가 힘든 작업을 처리하고 스페이스를 관리하도록 하는 것은 어떠세요? 부적절한 트리거 콘텐츠를 신고하고 이전 함수에서 배운 대로 DB를 업데이트하는 테스트를 추가합니다. 즉, 기본적으로 이전 함수를 가져와 프롬프트를 변경하고 답변에 따라 DB를 업데이트합니다.
주의사항 생성형 AI의 출력은 예측할 수 없습니다. Gemini의 '광고 소재 출력'이 'on rails' 상태인지 확인합니다. 0~1의 신뢰도 점수, JSON 등 결정적인 답변을 요청할 수 있습니다. 다음과 같은 다양한 방법으로 이를 달성할 수 있습니다. * Python 라이브러리 pydantic
, langchain
사용 * Gemini 구조화된 출력 사용
팁 여러 함수를 사용하거나 다음과 같이 JSON 답변을 강제하는 단일 프롬프트를 사용할 수 있습니다('Gemini 구조화된 출력'과 함께 사용하면 효과적임).
이 이미지를 생성하려면 어떤 프롬프트를 사용해야 하나요?
{
"description": "This is the picture of an arrosticino",
"suitable": TRUE
}
프롬프트에 추가 필드를 추가하여 다음과 같은 유용한 정보를 얻을 수 있습니다. 좋은 점이 있나요? 나쁜 점이 있나요? 이 장소를 아시나요? 텍스트가 있나요 (OCR이 그 어느 때보다 쉬워짐)?
goods
: '맛있는 음식처럼 보이네요'bads
: '건강에 좋지 않은 음식처럼 보입니다'OCR
: "Da consumare preferibilmente prima del 10 Novembre 2024"location
: 'Pescara, Lungomare'
N 결과에는 N 함수가 있는 것이 보통 더 좋지만, 10가지 작업을 수행하는 함수를 만드는 것도 매우 보람 있는 일입니다. 방법은 리카르도의 도움말을 참고하세요.
가능한 오류 (주로 IAM / 권한)
이 솔루션을 처음 개발했을 때 IAM 권한 문제가 발생했습니다. 공감을 얻고 문제를 해결하는 방법에 대한 아이디어를 제공하기 위해 여기에 추가하겠습니다.
오류: 서비스 계정에 권한이 충분하지 않음
- GCS 버킷을 수신하는 GCF 함수를 배포하려면 그림과 같이 작업에 사용하는 서비스 계정에 적절한 권한을 설정해야 합니다.
EventArc API도 사용 설정해야 할 수 있습니다. 완전히 사용할 수 있게 되기까지 몇 분 정도 걸립니다.
오류: Cloud Run 호출자가 누락됨
- GCF 권한 부여를 위한 UI의 또 다른 의견은 다음과 같습니다 ( Cloud Run 호출자 역할).
이 오류는 이미지에서 명령어를 실행하여 수정할 수 있습니다. 이 명령어는 fix-permissions.sh와 유사합니다.
이 문제는 https://cloud.google.com/functions/docs/securing/authenticating에 설명되어 있습니다.
오류: 메모리 한도 초과됨
처음 실행했을 때 로그에 '사용된 270MiB로 메모리 제한 244MiB 초과'라고 표시될 수 있습니다. 메모리 한도를 늘리는 것을 고려하세요(https://cloud.google.com/functions/docs/configuring/memory 참고). GCF에 RAM을 다시 추가합니다. UI에서 이 작업을 매우 쉽게 할 수 있습니다. 다음과 같은 조정이 적용될 수 있습니다.
또는 Cloud Run 배포 스크립트를 수정하여 MEM/CPU를 늘릴 수도 있습니다. 이 작업은 시간이 조금 더 걸립니다.
오류: PubSub 게시됨
GCF v1으로 트리거를 만들면 다음과 같은 오류가 한 번 발생했습니다.
이 문제는 IAM으로 이동하여 서비스 계정에 'Pub/Sub 게시자' 역할을 부여하면 쉽게 해결할 수 있습니다.
오류: Vertex AI가 사용되지 않음
다음 오류가 표시되는 경우:
권한 거부: 403 Vertex AI API가 이전에 YOUR_PROJECT 프로젝트에 사용되지 않았거나 사용 중지되었습니다. https://console.developers.google.com/apis/api/aiplatform.googleapis.com/overview?project=YOR_PROJECT 페이지를 방문하여 사용 설정한 후 다시 시도하세요.
Vertex AI API를 사용 설정하기만 하면 됩니다. 필요한 모든 API를 사용 설정하는 가장 쉬운 방법은 다음과 같습니다.
- https://console.cloud.google.com/vertex-ai
- '모든 권장 API 사용 설정'을 클릭합니다.
오류: EventArc 트리거를 찾을 수 없습니다.
이 오류가 표시되면 함수를 다시 배포하세요.
오류: 400 서비스 에이전트가 프로비저닝되고 있습니다
400 서비스 에이전트가 프로비저닝되고 있습니다 ( https://cloud.google.com/vertex-ai/docs/general/access-control#service-agents). 제공된 Cloud Storage 파일을 읽으려면 서비스 에이전트가 필요합니다. 잠시 후 다시 시도해 주세요.
이 경우 잠시 기다리거나 Google 직원에게 문의하세요.
10. 모듈 8: 가용성 SLO 만들기
이 챕터에서는 다음을 달성하고자 합니다.
- SLI 만들기
- SLI를 기반으로 SLO 만들기
- SLO 기반 알림 만들기
Riccardo가 Google Cloud의 SRE / DevOps 분야에서 일하고 있으므로 저자에게는 매우 중요한 주제입니다.
(개방형) 이 앱의 SLI 및 SLO 만들기
앱이 다운되었을 때 이를 알 수 없다면 앱이 얼마나 유용할까요?
SLO란 무엇인가요?
이런, Google에서 SLO를 발명했습니다. 자세한 내용은 다음을 참고하세요.
- SRE 도서 - 2장 - SLO 구현 ( 👉 더 많은 SRE 도서)
- SLO의 기술 ( 멋진 동영상) 서비스에 적합한 SLO를 만드는 방법을 자세히 알아볼 수 있는 훌륭한 교육입니다.
- Coursera의 SRE 과정 제가 기여했습니다.
1단계: 가용성 SLI/SLO 만들기
가장 쉽고 측정하려는 것 중 가장 중요한 것일 수 있는 가용성 SLO부터 시작해 보겠습니다.
다행히 Cloud Run에는 Istio 덕분에 사전 빌드된 SLO 지원이 제공됩니다.
앱이 Cloud Run에 있으면 이를 달성하기가 매우 간단하며 30초가 걸립니다.
- Cloud Run 페이지로 이동합니다.
- 앱을 클릭하거나 선택합니다.
SLOs
탭을 선택합니다.- '+ SLO 만들기'를 클릭합니다.
- 가용성, 요청 기반
- 계속
- Calendar Month / 99%
- 'SLO 만들기'를 클릭합니다.
2단계: 이 SLO에 대한 알림 설정하기
다음과 같이 2개의 알림을 만드는 것이 좋습니다.
- 이메일로 알림을 보내는 소진율이 낮은 항목 ('Slowburn') 하나 (우선순위가 낮은 티켓 시뮬레이션)
- SMS를 통해 알림을 보내는 소진율이 높은 ('Fastburn') 항목 (우선순위가 높은 티켓 / 무선 호출기 시뮬레이션)
이전에 사용한 SLO tab
으로 이동합니다.
다음 단계를 두 번 실행합니다.
- 오른쪽의 더하기 기호가 있는 🔔 버튼인 'SLO 알림 만들기'를 클릭합니다.
- 전환 확인 기간, 소진율 기준:
- [FAST] 첫 번째:
60
분 /10
회 - [느림] 두 번째:
720
분 /2
회 - 알림 채널: 알림 채널 관리를 클릭합니다.
- 먼저 '이메일' -> '새로 추가' -> ..
- 두 번째 방법은 'SMS' -> '새로 추가' -> '휴대전화에서 인증'입니다.
- 팁: 이름에 그림 이모티콘을 사용하는 것이 좋습니다. 데모에 적합합니다.
- 완료되면 오른쪽 상단의 큰 X를 클릭합니다.
- 전화번호를 먼저 선택하고 (빠름) 이메일을 다음에 선택합니다 (느림).
- 다음과 같은 샘플 문서를 추가합니다.
[PHP Amarcord] Riccardo told me to type sudo reboot or to check documentation in http://example.com/playbooks/1.php but I guess he was joking
.
빙고!
최종 결과
가용성에 대한 SLO 1개와 알림 2개가 작동하고 이메일과 휴대전화로 알림이 전송되면 이 연습이 완료된 것으로 간주할 수 있습니다.
원하는 경우 지연 시간을 추가할 수 있습니다 (추가하는 것이 좋습니다). 더 복잡한 지연 시간을 추가할 수도 있습니다. 지연 시간의 경우 적절하다고 생각되는 지연 시간을 선택합니다. 확실하지 않은 경우 200ms를 선택하세요.
11. 다음 단계
모든 것을 완료했는데 무엇이 누락되었나요?
다음 사항을 고려해 보세요.
Gemini와 함께 즐기기
Gemini는 다음 두 가지 버전으로 사용할 수 있습니다.
- Vertex AI 7장 (GCF+Gemini)에서 살펴본 GCP와 얽혀 있는 '엔터프라이즈 방식' 모든 인증이 마법처럼 작동하고 서비스가 아름답게 상호 연결됩니다.
- Google AI '소비자 방식' 여기에서 Gemini API 키를 가져와 기존 워크로드 (독점 작업, 기타 클라우드, localhost 등)에 연결할 수 있는 작은 스크립트를 빌드합니다. API 키를 대체하기만 하면 코드가 마법처럼 작동합니다.
자체 반려동물 프로젝트를 통해 (2)를 탐색해 보시기 바랍니다.
UI 리프팅
UI는 잘 못해. 하지만 Gemini는 가능합니다. 단일 PHP 페이지를 가져와 다음과 같이 말할 수 있습니다.
I have a VERY old PHP application. I want to touch it as little as possible. Can you help me:
1. add some nice CSS to it, a single static include for tailwind or similar, whatever you prefer
2. Transform the image print with description into cards, which fit 4 per line in the canvas?
Here's the code:
-----------------------------------
[Paste your PHP page, for instance index.php - mind the token limit!]
Cloud Build를 한 번만 실행하면 5분 이내에 이 작업을 쉽게 완료할 수 있습니다. :)
Gemini의 대답은 완벽했습니다 (즉, 아무것도 변경하지 않아도 됨).
다음은 저자의 개인 앱에 표시되는 새로운 레이아웃입니다.
참고: 코드를 가져가는 것이 아니라 Gemini가 나만의 창의적인 UI/프런트엔드 제약 조건으로 코드를 작성하도록 유도하기 위해 코드가 이미지로 붙여넣어집니다. 이후에 매우 사소한 변경사항만 남게 됩니다.
보안
이 앱을 적절하게 보호하는 것은 이 4시간 워크숍의 목표가 아닙니다. 이 앱을 보호하면 워크숍을 완료하는 데 걸리는 시간이 1~2배 늘어나기 때문입니다.
하지만 이 주제는 매우 중요합니다. SECURITY
에 몇 가지 아이디어를 모아 두었습니다.
12. 축하합니다.
축하합니다 🎉🎉🎉. Google Cloud를 사용하여 기존 PHP 애플리케이션을 성공적으로 현대화했습니다.
이 Codelab에서 알아본 내용은 다음과 같습니다.
- Google Cloud SQL에 데이터베이스를 배포하는 방법과 기존 데이터베이스를 마이그레이션하는 방법을 알아봅니다.
- Docker 및 Buildpack으로 PHP 애플리케이션을 컨테이너화하고 Google Cloud Artifact Registry에 이미지를 저장하는 방법
- 컨테이너화된 앱을 Cloud Run에 배포하고 Cloud SQL로 실행하는 방법
- Google Secret Manager를 사용하여 민감한 구성 매개변수 (예: DB 비밀번호)를 비밀리에 저장/사용하는 방법
- GitHub 저장소에 코드를 푸시할 때마다 Google Cloud Build를 사용하여 PHP 앱을 자동으로 빌드하고 배포하도록 CI/CD 파이프라인을 설정하는 방법
- Cloud Storage를 사용하여 앱 리소스를 '클라우드화'하는 방법
- 서버리스 기술을 활용하여 앱 코드를 수정하지 않고 Google Cloud 기반으로 멋진 워크플로를 빌드하는 방법
- 적합한 사용 사례에 Gemini 멀티모달 기능을 사용합니다.
- Google Cloud 내에서 SRE 원칙 구현
Google Cloud를 사용한 애플리케이션 현대화 여정을 시작하기에 좋은 출발입니다.
🔁 의견
이 워크숍에 대한 경험을 알려 주시려면 이 의견 양식을 작성해 주세요.
특히 자랑스러운 코드 조각에 대한 의견과 PR을 환영합니다.
🙏 감사합니다.
작성 및 솔루션 테스트에 도움을 주신 Datatonic의 미르코 질리올리님과 마우리치오 입살레님께 감사드립니다.