集装箱
在Cloudflare工人上与集装箱互动的班级.
特征
- HTTP 请求代理和 WebSocket 转发
- 在HTTPS支助下,由主机或全覆盖处理器拦截外部请求
- 主机允许/ 拒绝列表与 glob 模式匹配
- 简单的集装箱生命周期管理(起动和停放集装箱)
- 集装箱生命周期事件的事件钩子(启动、停止、错误)
- 根据请求更新的可配置睡眠超时
- 装入平衡公用事业
安装
npm install @cloudflare/containers
基本示例
import { Container, getContainer, getRandom } from '@cloudflare/containers';
export class MyContainer extends Container {
// Configure default port for the container
defaultPort = 8080;
// After 1 minute of no new activity, shutdown the container
sleepAfter = '1m';
}
export default {
async fetch(request, env) {
const pathname = new URL(request.url).pathname;
// If you want to route requests to a specific container,
// pass a unique container identifier to .get()
if (pathname.startsWith('/specific/')) {
// In this case, each unique pathname will spawn a new container
const container = env.MY_CONTAINER.getByName(pathname);
return await container.fetch(request);
}
// Note: this is a temporary method until built-in autoscaling and load balancing are added.
// If you want to route to one of many containers (in this case 5), use the getRandom helper.
// This load balances incoming requests across these container instances.
let container = await getRandom(env.MY_CONTAINER, 5);
return await container.fetch(request);
},
};
API 参考
Container 类
这个 Container class 扩展了容器阻塞的持久对象,以提供额外的容器特定功能.
属性
-
defaultPort?与容器通信时使用的可选默认端口 。 如果未设置此选项, 或者您想要瞄准您的容器上的特定端口, 您可以指定端口
fetch(switchPort(req, 8080))或者说containerFetch(req, 8080)。 。 。 . -
requiredPorts?集装箱启动时应当检查可用的端口序列。 用于
startAndWaitForPorts在未提供特定端口的情况下. -
sleepAfter容器在无活性情况下能活多久(格式:数为秒,或"5m","30s","1h"等字符串).
默认为"10m",指集装箱级持久对象在10分钟内没有收到请求后会关闭容器.
以下属性用于设定启动容器时的默认值, 但可以通过将数值传递到 startAndWaitForPorts() 或者说 start()。 。 。 .
-
env?: Record<string, string>启动时要传递到容器的环境变量 .
-
entrypoint?: string[]指定一个切入点来覆盖图像默认值.
-
enableInternet: boolean是否允许容器的互联网访问 .
默认为
true。 。 。 . -
interceptHttps: boolean何时
true,出站的HTTPS流量也通过与HTTP相同的处理链被拦截. 容器必须信任 Cloudflare 提供的 CA 证书/etc/cloudflare/certs/cloudflare-containers-ca.crt。见 Egress 文件 每次分发的设置指令.默认为
false。 。 。 . -
allowedHosts: string[]主机名模式的白名单 。 当非空时,只有匹配的主机才能通过允许检查进行;其他的都被屏蔽了(HTTP 520). 支持简单的模糊模式
*匹配任意字符序列(例如.'*.example.com') (中文(简体) ). -
deniedHosts: string[]主机名模式块列表 。 匹配主机无条件被屏蔽(HTTP 520),压倒了处理器链中其他所有,包括每个主机处理器. 支持与
allowedHosts。 。 。 . -
pingEndpoint: string指定容器类的端点,以检查是否启动基本实例. 这不需要由大多数人来设定, 只有在你喜欢集装箱主管时才使用 当容器启动时,它会击中容器的另一端. 看着
pingEndpoint可同时包括主机名和路径。 你们可以 设定container/health,含义"container"将是沿Host页眉,以及"/health"路径.默认为
ping。 。 。 .
方法
生命周期钩
当容器状态过渡时,这些生命周期方法会自动被称作. 取代这些方法使用这些钩子.
见 此示例。 。 。 .
-
onStart()当容器成功启动时调用 .
- 当状态从
stopped- > (中文)running, (中文(简体) ),running- > (中文)healthy
- 当状态从
-
onStop()集装箱关机时打过电话.
-
onError(error)当容器遇到错误时调用,并默认日志并丢出错误.
-
onActivityExpired()活动到期时调用. 在上次活动之后, 容器将继续运行一段时间 - 这个时间长度由
sleepAfter。 。 。 . 默认情况下,它会用SIGTERM,但你可以推翻这个行为, 就像其他生命周期钩。 然而,如果不在这里停止容器,活性追踪器会被更新,这个生命周期钩在计时器再过期时再次被叫来.
集装箱方法
-
fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>向容器转发 HTTP 请求 .
如果您想瞄准容器上的特定端口,而不是默认端口,应当使用
switchPort像这样:const container = env.MY_CONTAINER.getByName('id'); await container.fetch(switchPort(request, 8080));请确保您提供带有开关的端口或指定带有开关的端口
defaultPort属性.您必须使用
fetch而不是说containerFetch如果您想要转发 websockets .请注意,当您调用任何获取函数时,活动会自动被更新(在上次活动后开始后睡眠),如果尚未运行,容器会启动 .
-
containerFetch(...)说明:
containerFetch不与 websockets 工作.向容器发送 HTTP 请求 。 支持两个标准获取 API 签名 :
containerFetch(request, port?): 带有请求对象的传统签名containerFetch(url, init?, port?): 有 URL 字符串/对象和 RequestInit 选项的标准获取式签名
-
startAndWaitForPorts(args: StartAndWaitForPortsOptions): Promise<void>启动容器,然后等待指定端口做好准备。 优先事项
ports传到函数,然后requiredPorts如果设置,那么defaultPort。 。 。 .interface StartAndWaitForPortsOptions { startOptions?: { /** Environment variables to pass to the container */ envVars?: Record<string, string>; /** Custom entrypoint to override container default */ entrypoint?: string[]; /** Whether to enable internet access for the container */ enableInternet?: boolean; }; /** Ports to check */ ports?: number | number[]; cancellationOptions?: { /** Abort signal to cancel start and port checking */ abort?: AbortSignal; /** Max time to wait for container to start, in milliseconds */ instanceGetTimeoutMS?: number; /** Max time to wait for ports to be ready, in milliseconds */ portReadyTimeoutMS?: number; /** Polling interval for checking container has started or ports are ready, in milliseconds */ waitInterval?: number; }; } -
start(startOptions?: ContainerStartConfigOptions, waitOptions?: WaitOptions)启动集装箱,不等待任何港口做好准备.
你最好用这个代替
startAndWaitForPorts如果你想的话:- 在端口可用之前不屏蔽启动容器
- 初始化不暴露端口的容器
- 单独进行自定义端口可用性检查
选项 :
interface ContainerStartConfigOptions { /** Environment variables to pass to the container */ envVars?: Record<string, string>; /** Custom entrypoint to override container default */ entrypoint?: string[]; /** Whether to enable internet access for the container */ enableInternet?: boolean; } interface WaitOptions { /** The port number to check for readiness */ portToCheck: number; /** Optional AbortSignal, use this to abort waiting for ports */ signal?: AbortSignal; /** Number of attempts to wait for port to be ready */ retries?: number; /** Time to wait in between polling port for readiness, in milliseconds */ waitInterval?: number; } -
stop(signal = SIGTERM): Promise<void>向容器发送指定的信号。 触发器
onStop。 。 。 . -
destroy(): Promise<void>强制销毁容器(发送)
SIGKILL) (中文(简体) ). 触发器onStop。 。 。 . -
getState(): Promise<State>获取当前容器状态 .
type State = { lastChange: number; } & ( | { // 'running' means that the container is trying to start and is transitioning to a healthy status. // onStop might be triggered if there is an exit code, and it will transition to 'stopped'. status: 'running' | 'stopping' | 'stopped' | 'healthy'; } | { status: 'stopped_with_code'; exitCode?: number; } ); -
renewActivityTimeout()手动更新容器活度超时(延长容器寿命).
外出拦截
当您想要控制容器所能达到的时使用出站拦截,或者通过工人代码代理出站请求.
-
setOutboundByHost(host: string, method: string): Promise<void>将特定主机名从
static outboundHandlers。 。 。 . -
setOutboundByHosts(handlers: Record<string, string>): Promise<void>立即替换所有运行时主机特定覆盖 .
-
removeOutboundByHost(host: string): Promise<void>删除运行时主机特定覆盖 .
-
setOutboundHandler(method: string): Promise<void>设置所有外出处理器到命名处理器
static outboundHandlers。 。 。 . -
setAllowedHosts(hosts: string[]): Promise<void>在运行时替换允许的主机列表 .
-
setDeniedHosts(hosts: string[]): Promise<void>运行时替换已拒绝的主机列表 .
-
allowHost(hostname: string): Promise<void>在允许列表中添加单个主机.
-
denyHost(hostname: string): Promise<void>在拒绝的列表中添加单个主机.
-
removeAllowedHost(hostname: string): Promise<void>从允许的列表中删除主机.
-
removeDeniedHost(hostname: string): Promise<void>从拒绝的列表中删除主机.
要配置类本身的截取:
-
static outbound = (req, env, ctx) => Response接通所有出入境请求的人.
-
static outboundByHost = { [host]: handler }精确主机名匹配的每个主机处理器, 如
google.com或者一个IP地址. -
static outboundHandlers = { [name]: handler }在运行时可选择的指定处理器
setOutboundHandler财务报告和审定财务报表setOutboundByHost。 。 。 .
处理顺序( 第一局胜出) :
- 拒绝主机 - 如果主机名称匹配任何
deniedHosts模式,请求被屏蔽(HTTP 520). 超越一切诸相. - 允许的主机门 如果
allowedHosts是非空的,主机名不匹配,请求被屏蔽(HTTP 520). 何时allowedHosts此步骤已跳过. - 每个东道主处理器运行时间 —— 说
setOutboundByHost()覆盖 - 静态/ 主机处理器 —— 说
outboundByHost - 运行时间控制器 —— 说
setOutboundHandler()覆盖 - 静态控制器 —— 说
outbound - 允许主机互联网回落 - 如果主机名匹配
allowedHosts但上面没有处理者处理过,请求被传送到互联网(即使enableInternet实值false) (中文(简体) ). enableInternet倒计时 如果true请求会传到互联网上.- 默认拒绝 ——请求被封(HTTP 520).
-
schedule<T = string>(when: Date | number, callback: string, payload?: T): Promise<Schedule<T>>选项 :
when: 何时执行任务(日期对象或秒数延迟)callback: 要调用为字符串的函数名称payload: 数据传递给召回
而不是使用默认的提醒处理器, 使用
schedule()换句话说 默认的报警处理器负责更新容器活性并保持耐用物体活性. 您可以覆盖alarm()由于其功能目前对于管理集装箱生命周期至关重要,我们建议调用schedule来安排任务.
工具函数
-
getRandom(binding, instances?: number)在 N 实例中获取一个随机的容器实例 。 这对于负载平衡有用. 返回容器的根. 见 实例。 。 。 .
-
getContainer(binding, name?: string)帮助获得特定容器实例根茎.譬如说.
const container = getContainer(env.CONTAINER, "unique-id")如果没有提供名称,则使用"参考-singleton-container".
实例
HTTP 有生命周期钩的示例
import { Container } from '@cloudflare/containers';
export class MyContainer extends Container {
// Configure default port for the container
defaultPort = 8080;
// Set how long the container should stay active without requests
// Supported formats: "10m" (minutes), "30s" (seconds), "1h" (hours), or a number (seconds)
sleepAfter = '10m';
// Lifecycle method called when container starts
override onStart(): void {
console.log('Container started!');
}
// Lifecycle method called when container shuts down
override onStop(): void {
console.log('Container stopped!');
// you can also call startAndWaitForPorts() again
// this.startAndWaitForPorts();
}
// Lifecycle method called on errors
override onError(error: unknown): any {
console.error('Container error:', error);
throw error;
}
// Lifecycle method when the container class considers the activity to be expired
override onActivityExpired() {
console.log('Container activity expired');
await this.destroy();
}
// Custom method that will extend the container's lifetime
async performBackgroundTask(): Promise<void> {
// Do some work...
// Renew the container's activity timeout
await this.renewActivityTimeout();
console.log('Container activity timeout extended');
}
// Additional methods can be implemented as needed
}
WebSocket 支持
容器类自动支持代理WebSocket连接您的容器。 WebSocket连接是双向的代理,消息以双向传输. 当WebSocket消息发送或收到时,容器也会自动更新活动超时.
// Connect to a WebSocket on port 9000
const response = await container.fetch(switchPort(request, 9000));
备注 Websockets 不支持 containerFetch。 。 。 .
容器配置示例
您可以通过设置环境变量、入站点和网络访问的实例属性来配置容器起始的默认值:
import { Container } from '@cloudflare/containers';
export class ConfiguredContainer extends Container {
// Default port for the container
defaultPort = 9000;
// Set the timeout for sleeping the container after inactivity
sleepAfter = '2h';
// Environment variables to pass to the container
envVars = {
NODE_ENV: 'production',
LOG_LEVEL: 'info',
APP_PORT: '9000',
};
// Custom entrypoint to run in the container
entrypoint = ['node', 'server.js', '--config', 'production.json'];
// Enable internet access for the container
enableInternet = true;
// These configuration properties will be used automatically
// when the container starts
}
您也可以在每封邮件中按 start 或者说 startAndWaitForPorts
外出拦截
这样你就可以拦截到 集装箱对外界的要求.
您必须导出 ContainerProxy 从您的工人入境点截取出入境工作:
export { ContainerProxy } from '@cloudflare/containers';
import { Container, OutboundHandlerContext } from '@cloudflare/containers';
export class MyContainer extends Container {
defaultPort = 8080;
enableInternet = false;
interceptHttps = true; // also intercept HTTPS outbound traffic
// Only allow these hosts through the egress chain
allowedHosts = ['google.com', 'github.com', 'api.stripe.com'];
// Block these hosts unconditionally, even if they appear in allowedHosts
deniedHosts = ['evil.com', '*.malware.net'];
static outboundByHost = {
'google.com': (_req: Request, _env: unknown, ctx: OutboundHandlerContext) => {
return new Response('hi ' + ctx.containerId + ' i am google');
},
};
static outboundHandlers = {
async github(_req: Request, _env: unknown, _ctx: OutboundHandlerContext) {
return new Response('i am github');
},
};
static outbound = (req: Request) => {
return new Response(`Hi ${req.url}, I can't handle you`);
};
async routeGithubThroughHandler(): Promise<void> {
await this.setOutboundByHost('github.com', 'github');
}
async makeEverythingUseGithubHandler(): Promise<void> {
await this.setOutboundHandler('github');
}
}
使用 outboundByHost 对于固定的东道主规则, outbound 对于默认的包罗万象,和 outboundHandlers 用于运行时您想要打开的重用名处理器。 使用 allowedHosts 财务报告和审定财务报表 deniedHosts 用于基于 glob 主机过滤(例如). '*.example.com') (中文(简体) ). 见 完整胶卷文件 用于HTTPS拦截的详细拦截策略和CA证书设置.
多个端口和自定义运行
您可以创建一个不使用默认端口的容器, 转而根据请求路径或其他因素将流量引导到不同的端口 :
import { Container } from '@cloudflare/containers';
export class MultiPortContainer extends Container {
// No defaultPort defined - we'll handle port specification manually
constructor(ctx: any, env: any) {
super(ctx, env);
}
/**
* Process an incoming request and route to different ports based on path
*/
async fetch(request: Request): Promise<Response> {
const url = new URL(request.url);
try {
if (url.pathname.startsWith('/api')) {
// API server runs on port 3000
return await this.containerFetch(request, 3000);
} else if (url.pathname.startsWith('/admin')) {
// Admin interface runs on port 8080
return await this.containerFetch(request, 8080);
} else {
// Public website runs on port 80
return await this.containerFetch(request, 80);
}
} catch (error) {
return new Response(`Error: ${error instanceof Error ? error.message : String(error)}`, {
status: 500,
});
}
}
}
使用标准获取 API 语法
您可以使用标准获取 API 语法的 ContexFetch 方法 :
import { Container } from '@cloudflare/containers';
export class FetchStyleContainer extends Container {
defaultPort = 8080;
async customHandler(): Promise<Response> {
try {
// Using the new fetch-style syntax
const response = await this.containerFetch('/api/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ query: 'example' }),
});
// You can also specify a port with this syntax
const adminResponse = await this.containerFetch(
'https://example.com/admin',
{ method: 'GET' },
3000 // port
);
return response;
} catch (error) {
return new Response(`Error: ${error instanceof Error ? error.message : String(error)}`, {
status: 500,
});
}
}
}
集装箱停放管理
集装箱类别包括一个自动闲置的超时功能,在一段时间后会关闭集装箱. 这有助于在不使用容器时节省资源.
import { Container } from '@cloudflare/containers';
export class TimeoutContainer extends Container {
// Configure default port for the container
defaultPort = 8080;
// Set timeout to 30 minutes of inactivity
sleepAfter = '30m'; // Supports "30s", "5m", "1h" formats, or a number in seconds
// Custom method that will extend the container's lifetime
async performBackgroundTask(data: any): Promise<void> {
console.log('Performing background task...');
// Manually renew the activity timeout, even though
// you have not made a request to the container
await this.renewActivityTimeout();
console.log('Container activity timeout renewed');
}
// Activity timeout is automatically renewed on fetch requests
async fetch(request: Request): Promise<Response> {
const url = new URL(request.url);
// Example endpoint to trigger background task
if (url.pathname === '/task') {
await this.performBackgroundTask();
return new Response(
JSON.stringify({
success: true,
message: 'Background task executed',
nextStop: `Container will shut down after ${this.sleepAfter} of inactivity`,
}),
{ headers: { 'Content-Type': 'application/json' } }
);
}
// For all other requests, forward to the container
// This will automatically renew the activity timeout
return this.containerFetch(request);
}
}
使用负载平衡
这个软件包包括 getRandom 向 N 例请求的帮助.
今后,将通过资源意识负荷平衡自动处理
当自动缩放设定为真实时, 但它尚未执行 .
import { Container, getContainer, getRandom } from '@cloudflare/containers';
export class MyContainer extends Container {
defaultPort = 8080;
}
export default {
async fetch(request: Request, env: any) {
const url = new URL(request.url);
// Example: Load balance across 5 container instances
if (url.pathname === '/api') {
const containerInstance = await getRandom(env.MY_CONTAINER, 5);
return containerInstance.fetch(request);
}
// Example: Direct request to a specific container
if (url.pathname.startsWith('/specific/')) {
const id = url.pathname.split('/')[2] || 'default';
const containerInstance = getContainer(env.MY_CONTAINER, id);
return containerInstance.fetch(request);
}
return new Response('Not found', { status: 404 });
},
};