use codebuild

This commit is contained in:
falsycat 2025-06-21 09:56:46 +09:00
parent 48d86e4479
commit 4847424d9b
6 changed files with 125 additions and 57 deletions

29
buildspec.yml Normal file
View File

@ -0,0 +1,29 @@
version: 0.2
phases:
install:
runtime-versions:
nodejs: 18
commands:
- echo cloning repository...
- git clone https://git.falsy.cat/falsycat/imbusy/ .
- find
- echo installing dependencies...
- cd frontend && npm ci && cd ..
- cd backend && npm ci && cd ..
build:
commands:
- echo building frontend...
- cd frontend && npm run build && cd ..
- echo building backend...
- cd backend && npm run build && cd ..
post_build:
commands:
- echo deploying frontend...
- aws s3 sync frontend/dist/ s3://$IMBUSY_FE_BUCKET --delete
- echo deploying backend...
- cd backend/dist && zip -r ../../backend.zip . && cd ../..
- aws s3 cp backend.zip s3://$IMBUSY_BE_BUCKET

View File

@ -7,18 +7,11 @@ import * as common from "./common";
const tags = common.tags;
const prefix = `${common.prefix}-backend`;
console.log("building backend...");
esbuild.buildSync({
entryPoints: ["../backend/src/index.ts"],
outfile: "../backend/dist/index.js",
bundle: true,
platform: "node",
target: "node18",
minify: true,
});
// ---- program bucket ----
export const bucket = new aws.s3.Bucket(`${prefix}-bucket`);
// ---- backend lambda ----
// ---- api lambda ----
const lambdaRole = new aws.iam.Role(`${prefix}-lambda-role`, {
tags,
assumeRolePolicy: aws.iam.assumeRolePolicyForPrincipal({
@ -35,9 +28,8 @@ const lambda = new aws.lambda.Function(`${prefix}-lambda`, {
runtime: "nodejs18.x",
handler: "index.main",
role: lambdaRole.arn,
code: new pulumi.asset.AssetArchive({
".": new pulumi.asset.FileArchive("../backend/dist/"),
}),
s3Bucket: bucket.arn,
s3Key: "lambda.zip",
});
new aws.cloudwatch.LogGroup(`${prefix}-lambda-log-group`, {
name: pulumi.interpolate`/aws/lambda/${lambda.name}`,
@ -60,7 +52,7 @@ new aws.dynamodb.Table(`${prefix}-db`, {
// ---- API Gateway ----
const api = new aws.apigatewayv2.Api(`${prefix}-api`, {
export const api = new aws.apigatewayv2.Api(`${prefix}-api`, {
tags,
protocolType: "WEBSOCKET",
routeSelectionExpression: "$request.body.action",
@ -105,8 +97,6 @@ new aws.iam.RolePolicy(`${prefix}-api-role-policy`, {
}`,
});
export const endpoint = pulumi.interpolate`${api.apiEndpoint}`;
// ---- cognito ----
const userPool = new aws.cognito.UserPool(`${prefix}-cognito-userpool`, {

View File

@ -1,4 +1,5 @@
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
export const tags = {
project: pulumi.getProject(),
@ -6,3 +7,5 @@ export const tags = {
};
export const prefix = `${tags.project}-${tags.env}`;
export const logGroupPrefix = `/falsycat/${tags.project}/${tags.env}/`;

79
infra/deployment.ts Normal file
View File

@ -0,0 +1,79 @@
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as fs from "fs";
import * as common from "./common";
import * as backend from "./backend";
import * as frontend from "./frontend";
const tags = common.tags;
const prefix = `${common.prefix}-deployment`;
// ---- role ----
const role = new aws.iam.Role(`${prefix}-role`, {
tags,
assumeRolePolicy: aws.iam.assumeRolePolicyForPrincipal({ Service: "codebuild.amazonaws.com" }),
});
new aws.iam.RolePolicyAttachment(`${prefix}-policy-codebuild`, {
role: role.name,
policyArn: aws.iam.ManagedPolicies.AWSCodeBuildDeveloperAccess,
});
new aws.iam.RolePolicy(`${prefix}-role-policy`, {
role: role.name,
policy: pulumi.all([backend.bucket.arn, frontend.bucket.arn]).apply(([be, fe]) => JSON.stringify({
Version: "2012-10-17",
Statement: [
{
Effect: "Allow",
Action: [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
Resource: [ `${be}/*`, `${fe}/*`, ],
},
{
Effect: "Allow",
Action: [
"s3:ListBucket",
],
Resource: [ be, fe, ],
},
{
Effect: "Allow",
Action: [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
],
Resource: "*",
},
]
})),
});
// ---- codebuild ----
const codebuild = new aws.codebuild.Project(`${prefix}-codebuild`, {
tags,
source: {
type: "NO_SOURCE",
buildspec: fs.readFileSync("../buildspec.yml", "utf-8"),
},
environment: {
computeType: "BUILD_GENERAL1_SMALL",
image: "aws/codebuild/standard:7.0",
type: "LINUX_CONTAINER",
environmentVariables: [
{ name: "IMBUSY_BE_BUCKET", value: backend.bucket.bucket, },
{ name: "IMBUSY_FE_BUCKET", value: frontend.bucket.bucket, },
],
},
serviceRole: role.arn,
artifacts: {
type: "NO_ARTIFACTS",
},
});

View File

@ -10,33 +10,18 @@ import * as common from "./common";
const tags = common.tags;
const prefix = `${common.prefix}-frontend`;
// ---- infra resouces ----
const bucket = new aws.s3.Bucket(`${prefix}-bucket`, {tags});
const oai = new aws.cloudfront.OriginAccessIdentity(`${prefix}-oai`);
const bucketPolicy = new aws.s3.BucketPolicy(`${prefix}-bucket-policy`, {
bucket: bucket.bucket,
policy: pulumi.all([oai.iamArn, bucket.bucket]).apply(([a, b]) => JSON.stringify({
Version: "2012-10-17",
Statement: [{
Effect: "Allow",
Principal: {
AWS: a,
},
Action: ["s3:GetObject"],
Resource: [`arn:aws:s3:::${b}/*`],
}],
})),
});
// ---- bucket ----
export const bucket = new aws.s3.Bucket(`${prefix}-bucket`, {tags});
const bucketOai = new aws.cloudfront.OriginAccessIdentity(`${prefix}-oai`);
// ---- cloudfront ----
export const cloudfront = new aws.cloudfront.Distribution(`${prefix}-cloudfront`, {
tags,
origins: [{
domainName: bucket.bucketRegionalDomainName,
originId: bucket.arn,
s3OriginConfig: {
originAccessIdentity: oai.cloudfrontAccessIdentityPath,
originAccessIdentity: bucketOai.cloudfrontAccessIdentityPath,
},
}],
enabled: true,
@ -73,23 +58,3 @@ export const cloudfront = new aws.cloudfront.Distribution(`${prefix}-cloudfront`
cloudfrontDefaultCertificate: true,
},
});
// ---- file uploads ----
(async () => {
const cwd = "../frontend/dist/";
const stats = await fs.stat(cwd);
if (!stats.isDirectory()) {
throw new Error("build the frontend firstly");
}
const files = await fg("**/*", {cwd, dot: true});
for (const file of files) {
new aws.s3.BucketObject(file, {
bucket: bucket,
source: new pulumi.asset.FileAsset(cwd+file),
contentType: mime.getType(file) || "application/octet-stream",
key: file,
});
}
})();

View File

@ -4,5 +4,7 @@ import * as aws from "@pulumi/aws";
import * as backend from "./backend";
import * as frontend from "./frontend";
import "./deployment";
export const frontendDomain = frontend.cloudfront.domainName;
export const backendEndpoint = backend.endpoint;
export const backendEndpoint = backend.api.apiEndpoint;