From 5aa4a4cdc5377d82b3b8f2d23a59012eec55a6e4 Mon Sep 17 00:00:00 2001 From: "fangyaozheng@bytedance.com" Date: Mon, 8 Sep 2025 18:40:45 +0800 Subject: [PATCH 1/2] supply docs and fix image deploy issues --- docs/docs/deploy.md | 35 ++++++ veadk/cli/cli_pipeline.py | 105 ++++++++++-------- .../ve_code_pipeline/ve_code_pipeline.py | 6 +- veadk/integrations/ve_cr/ve_cr.py | 25 ++++- 4 files changed, 117 insertions(+), 54 deletions(-) diff --git a/docs/docs/deploy.md b/docs/docs/deploy.md index b99b5636..6790d169 100644 --- a/docs/docs/deploy.md +++ b/docs/docs/deploy.md @@ -237,3 +237,38 @@ Confirm delete cloud app my-agent-app? (y/N): y - `agent_module` 自定义的 agent 模块 - `__init__.py` 必须包含 `from . import agent` 语句 - `agent.py` 定义 agent 实例,必须包含 `root_agent=...` 全局变量导出 + +## 持续交付 + +VeADK 内置了[火山引擎持续交付](https://www.volcengine.com/product/cp)产品来便捷您的部署与持续交付。结合[火山引擎镜像仓库](https://www.volcengine.com/product/cr)产品,能够通过镜像将您的项目持续交付到火山引擎 FaaS 服务。 + +> 通过容器部署到云上是最佳实践。 + +使用命令`veadk pipeline`来连结您的代码仓库与火山引擎镜像仓库、持续交付服务。命令的主要工作流程: + +1. 帮助您在 VeFaaS 上创建一个含有模板镜像(Simple FastAPI)的镜像函数 +2. 将持续交付服务绑定至您的 Github 仓库与创建好的 VeFaaS 函数 + +随后,您可以在您的 Github 仓库中进行您的第一次提交,您的仓库项目将会被自动: + +1. 打包为镜像, +2. 推送至您的镜像仓库 +3. 构建部署到 VeFaaS 函数中 + +命令`veadk pipeline`参数: + +| 参数 | 说明 | 默认值 / 必填 | +|------|------|---------------| +| `--github-url` | Github 仓库 URL | **必填** | +| `--github-branch` | Github 项目的分支 | **必填** | +| `--veadk-version` | VeADK 版本,可选值:`preview`(主分支)、`latest`(最新稳定版)、`x.x.x`(具体版本号) | 当前版本号 | +| `--github-token` | Github Token,用于管理项目 | **必填** | +| `--volcengine-access-key` | 火山引擎 Access Key | 使用环境变量 `VOLCENGINE_ACCESS_KEY` | +| `--volcengine-secret-key` | 火山引擎 Secret Key | 使用环境变量 `VOLCENGINE_SECRET_KEY` | +| `--pipeline-region` | 火山引擎 CodePipeline 区域 | `cn-beijing` | +| `--cr-instance-name` | 火山引擎容器镜像仓库实例名 | `veadk-user-instance` | +| `--cr-namespace-name` | 火山引擎容器镜像仓库命名空间 | `veadk-user-namespace` | +| `--cr-repo-name` | 火山引擎容器镜像仓库 Repo 名称 | `veadk-user-repo` | +| `--vefaas-function-id` | 火山引擎 FaaS 函数 ID(要求为镜像函数),如未设置,将自动创建新函数 | - | + +**注意:**启动命令的目录中请提供 `config.yaml` 文件来将您的环境变量记录到云上。 diff --git a/veadk/cli/cli_pipeline.py b/veadk/cli/cli_pipeline.py index 66efe819..83946b3a 100644 --- a/veadk/cli/cli_pipeline.py +++ b/veadk/cli/cli_pipeline.py @@ -15,16 +15,21 @@ import warnings import click -from veadk.version import VERSION + from veadk.config import getenv -from veadk.integrations.ve_code_pipeline.ve_code_pipeline import VeCodePipeline -from veadk.integrations.ve_faas.ve_faas import VeFaaS -from veadk.integrations.ve_cr.ve_cr import VeCR from veadk.consts import ( DEFAULT_CR_INSTANCE_NAME, DEFAULT_CR_NAMESPACE_NAME, DEFAULT_CR_REPO_NAME, ) +from veadk.integrations.ve_code_pipeline.ve_code_pipeline import VeCodePipeline +from veadk.integrations.ve_cr.ve_cr import VeCR +from veadk.integrations.ve_faas.ve_faas import VeFaaS +from veadk.utils.logger import get_logger +from veadk.version import VERSION + +logger = get_logger(__name__) + warnings.filterwarnings( "ignore", category=UserWarning, module="pydantic._internal._fields" @@ -65,9 +70,9 @@ def _create_cr(volcengine_settings: dict[str, str], cr_settings: dict[str, str]) @click.command() @click.option( - "--base-image-tag", - required=True, - help=f"Base VeADK image tag can be 'preview', 'latest', or a VeADK version (e.g., {VERSION})", + "--veadk-version", + default=VERSION, + help=f"Base VeADK image tag can be 'preview', 'latest', or a specific VeADK version (e.g., {VERSION})", ) @click.option( "--github-url", @@ -76,8 +81,8 @@ def _create_cr(volcengine_settings: dict[str, str], cr_settings: dict[str, str]) ) @click.option( "--github-branch", - default="main", - help="The github branch of your project, default is main", + required=True, + help="The github branch of your project", ) @click.option( "--github-token", @@ -85,58 +90,52 @@ def _create_cr(volcengine_settings: dict[str, str], cr_settings: dict[str, str]) help="The github token to manage your project", ) @click.option( - "--access-key", - default=getenv("VOLCENGINE_ACCESS_KEY"), + "--volcengine-access-key", + default=None, help="Volcengine access key, if not set, will use the value of environment variable VOLCENGINE_ACCESS_KEY", ) @click.option( - "--secret-key", - default=getenv("VOLCENGINE_SECRET_KEY"), + "--volcengine-secret-key", + default=None, help="Volcengine secret key, if not set, will use the value of environment variable VOLCENGINE_SECRET_KEY", ) @click.option( "--region", default="cn-beijing", - help="Volcengine region, default is cn-beijing", + help="Region for Volcengine VeFaaS, CR, and Pipeline. Default is cn-beijing", ) @click.option( "--cr-instance-name", default=DEFAULT_CR_INSTANCE_NAME, - help="Container Registry instance name, default is veadk-user-instance", + help="Volcengine Container Registry instance name, default is veadk-user-instance", ) @click.option( "--cr-namespace-name", default=DEFAULT_CR_NAMESPACE_NAME, - help="Container Registry namespace name, default is veadk-user-namespace", + help="Volcengine Container Registry namespace name, default is veadk-user-namespace", ) @click.option( "--cr-repo-name", default=DEFAULT_CR_REPO_NAME, - help="Container Registry repo name, default is veadk-user-repo", -) -@click.option( - "--cr-region", - default="cn-beijing", - help="Container Registry region, default is cn-beijing", + help="Volcengine Container Registry repo name, default is veadk-user-repo", ) @click.option( - "--function-id", + "--vefaas-function-id", default=None, help="Volcengine FaaS function ID, if not set, a new function will be created automatically", ) def pipeline( - base_image_tag: str, + veadk_version: str, github_url: str, github_branch: str, github_token: str, - access_key: str, - secret_key: str, + volcengine_access_key: str, + volcengine_secret_key: str, region: str, cr_instance_name: str, cr_namespace_name: str, cr_repo_name: str, - cr_region: str, - function_id: str, + vefaas_function_id: str, ) -> None: """Integrate a veadk project to volcengine pipeline for CI/CD""" @@ -144,36 +143,36 @@ def pipeline( "Welcome use VeADK to integrate your project to volcengine pipeline for CI/CD." ) + if not volcengine_access_key: + volcengine_access_key = getenv("VOLCENGINE_ACCESS_KEY") + if not volcengine_secret_key: + volcengine_secret_key = getenv("VOLCENGINE_SECRET_KEY") + volcengine_settings = { - "volcengine_access_key": access_key, - "volcengine_secret_key": secret_key, + "volcengine_access_key": volcengine_access_key, + "volcengine_secret_key": volcengine_secret_key, "volcengine_region": region, } cr_settings = { - "cr_domain": f"{cr_instance_name}-{cr_region}.cr.volces.com", + "cr_domain": f"{cr_instance_name}-{region}.cr.volces.com", "cr_instance_name": cr_instance_name, "cr_namespace_name": cr_namespace_name, "cr_repo_name": cr_repo_name, - "cr_region": cr_region, + "cr_region": region, } - _create_cr(volcengine_settings, cr_settings) - - click.echo("Using the following CR configuration:") - click.echo(f"Container Registry domain: {cr_settings['cr_domain']}") - click.echo(f"Container Registry namespace name: {cr_settings['cr_namespace_name']}") - click.echo(f"Container Registry region: {cr_settings['cr_region']}") - click.echo(f"Container Registry instance name: {cr_settings['cr_instance_name']}") - click.echo(f"Container Registry repo name: {cr_settings['cr_repo_name']}") - - if not function_id: + if not vefaas_function_id: click.echo( - "No Function ID specified. The system will create one automatically. Please specify a function name:" + "No Function ID specified. VeADK will create one automatically. Please specify a function name:" ) function_name = click.prompt( - "Function name", default="veadk-function", show_default=False + "Function name", default="veadk-image-function", show_default=False ) + + _create_cr(volcengine_settings, cr_settings) + + if not vefaas_function_id: vefaas_client = VeFaaS( access_key=volcengine_settings["volcengine_access_key"], secret_key=volcengine_settings["volcengine_secret_key"], @@ -184,15 +183,29 @@ def pipeline( image="veadk-cn-beijing.cr.volces.com/veadk/simple-fastapi:0.1", registry_name=cr_settings["cr_instance_name"], ) - click.echo(f"Created function {function_name} with ID: {function_id}") + logger.debug(f"Created function {function_name} with ID: {function_id}") client = VeCodePipeline( volcengine_access_key=volcengine_settings["volcengine_access_key"], volcengine_secret_key=volcengine_settings["volcengine_secret_key"], region=volcengine_settings["volcengine_region"], ) + + click.echo("=====================================================") + click.echo("Using the following configuration to create pipeline:") + click.echo(f"Use VeADK version: {veadk_version}") + click.echo(f"Github url: {github_url}") + click.echo(f"Github branch: {github_branch}") + click.echo(f"VeFaaS function name: {function_name}") + click.echo(f"VeFaaS function ID: {function_id}") + click.echo(f"Container Registry domain: {cr_settings['cr_domain']}") + click.echo(f"Container Registry namespace name: {cr_settings['cr_namespace_name']}") + click.echo(f"Container Registry region: {region}") + click.echo(f"Container Registry instance name: {cr_settings['cr_instance_name']}") + click.echo(f"Container Registry repo name: {cr_settings['cr_repo_name']}") + client.deploy( - base_image_tag=base_image_tag, + base_image_tag=veadk_version, github_url=github_url, github_branch=github_branch, github_token=github_token, diff --git a/veadk/integrations/ve_code_pipeline/ve_code_pipeline.py b/veadk/integrations/ve_code_pipeline/ve_code_pipeline.py index fd106912..8774b24a 100644 --- a/veadk/integrations/ve_code_pipeline/ve_code_pipeline.py +++ b/veadk/integrations/ve_code_pipeline/ve_code_pipeline.py @@ -16,7 +16,7 @@ from string import Template import requests -from veadk.config import getenv + from veadk.utils.logger import get_logger from veadk.utils.misc import formatted_timestamp from veadk.utils.volcengine_sign import ve_request @@ -109,8 +109,8 @@ def get_dockerfile(tag: str = "latest") -> str: class VeCodePipeline: def __init__( self, - volcengine_access_key: str = getenv("VOLCENGINE_ACCESS_KEY"), - volcengine_secret_key: str = getenv("VOLCENGINE_SECRET_KEY"), + volcengine_access_key: str, + volcengine_secret_key: str, region: str = "cn-beijing", ) -> None: self.volcengine_access_key = volcengine_access_key diff --git a/veadk/integrations/ve_cr/ve_cr.py b/veadk/integrations/ve_cr/ve_cr.py index 44abf582..30d052df 100644 --- a/veadk/integrations/ve_cr/ve_cr.py +++ b/veadk/integrations/ve_cr/ve_cr.py @@ -12,14 +12,15 @@ # See the License for the specific language governing permissions and # limitations under the License. -from veadk.utils.volcengine_sign import ve_request -from veadk.utils.logger import get_logger +import time + from veadk.consts import ( DEFAULT_CR_INSTANCE_NAME, DEFAULT_CR_NAMESPACE_NAME, DEFAULT_CR_REPO_NAME, ) -import time +from veadk.utils.logger import get_logger +from veadk.utils.volcengine_sign import ve_request logger = get_logger(__name__) @@ -63,6 +64,20 @@ def _create_instance(self, instance_name: str = DEFAULT_CR_INSTANCE_NAME) -> str ) logger.debug(f"create cr instance {instance_name}: {response}") + if "Error" in response["ResponseMetadata"]: + error_code = response["ResponseMetadata"]["Error"]["Code"] + error_message = response["ResponseMetadata"]["Error"]["Message"] + if error_code == "AlreadyExists.Registry": + logger.debug(f"cr instance {instance_name} already exists") + return instance_name + else: + logger.error( + f"Error create cr instance {instance_name}: {error_code} {error_message}" + ) + raise ValueError( + f"Error create cr instance {instance_name}: {error_code} {error_message}" + ) + while True: status = self._check_instance(instance_name) if status == "Running": @@ -71,7 +86,7 @@ def _create_instance(self, instance_name: str = DEFAULT_CR_INSTANCE_NAME) -> str raise ValueError(f"cr instance {instance_name} create failed") else: logger.debug(f"cr instance status: {status}") - time.sleep(5) + time.sleep(30) return instance_name @@ -142,7 +157,7 @@ def _create_namespace( error_code = response["ResponseMetadata"]["Error"]["Code"] error_message = response["ResponseMetadata"]["Error"]["Message"] if error_code == "AlreadyExists.Namespace": - logger.debug(f"cr namespace {namespace_name} already exists") + logger.warning(f"cr namespace {namespace_name} already exists") return namespace_name else: logger.error( From 2e48e51349d2652e01f6154208604eab6c13f19d Mon Sep 17 00:00:00 2001 From: "fangyaozheng@bytedance.com" Date: Mon, 8 Sep 2025 18:41:23 +0800 Subject: [PATCH 2/2] fix doc --- docs/docs/deploy.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/deploy.md b/docs/docs/deploy.md index 6790d169..4f883bf4 100644 --- a/docs/docs/deploy.md +++ b/docs/docs/deploy.md @@ -265,7 +265,7 @@ VeADK 内置了[火山引擎持续交付](https://www.volcengine.com/product/cp) | `--github-token` | Github Token,用于管理项目 | **必填** | | `--volcengine-access-key` | 火山引擎 Access Key | 使用环境变量 `VOLCENGINE_ACCESS_KEY` | | `--volcengine-secret-key` | 火山引擎 Secret Key | 使用环境变量 `VOLCENGINE_SECRET_KEY` | -| `--pipeline-region` | 火山引擎 CodePipeline 区域 | `cn-beijing` | +| `--region` | 火山引擎产品区域 | `cn-beijing` | | `--cr-instance-name` | 火山引擎容器镜像仓库实例名 | `veadk-user-instance` | | `--cr-namespace-name` | 火山引擎容器镜像仓库命名空间 | `veadk-user-namespace` | | `--cr-repo-name` | 火山引擎容器镜像仓库 Repo 名称 | `veadk-user-repo` |