CI/CDãã¤ãã©ã¤ã³ãæ§ç¯ããã«ããã£ã¦aws-cdkã«contributeãã話
ã¯ããã«
ããã«ã¡ã¯ãFinatextã§ã¨ã³ã¸ãã¢ããã¦ããç³æ©ï¼@bashi0501ï¼ã§ãã
Finatextã§ã¯ã³ã¼ãã«è¿ãã¨ããã§ã®å°ãããµã¤ãºã®testãéç解æã«CircleCI, GitHub Actionsãå©ç¨ããã¯ã©ã¦ãç°å¢ã¸ã®ãªãªã¼ã¹ãã¤ãã©ã¤ã³ã«ã¯ãã大ãããµã¤ãºã®ãã¹ããå®ç°å¢ã¨åããããã¯ã¼ã¯ã§å®è¡ãããããããã¤ã«ä½¿ãã¯ã¬ãã³ã·ã£ã«ãããã¿ã«ä»ã®ãµã¼ãã¹ã«ç½®ããããªãã¨ããçç±ããAWS CodeBuild, AWS CodePipelineã使ç¨ãã¦ãã¾ãã
ããã¾ã§ã¯CodePipelineã«ãããªãªã¼ã¹ãã¤ãã©ã¤ã³ãããã¸ã¡ã³ãã³ã³ã½ã¼ã«ãã丹精込ãã¦ãæ製ã§ä½ã£ã¦ãã¾ããããã以åã®ç°å³¶ã®è¨äºã§ããã£ãããã«50åè¿ãã®AWSã¢ã«ã¦ã³ããããä¸ã§ããã¾ã§ã®æ¹éã§ç¶ç¶ã»å±éãã¦ããã®ã¯å³ãããªã£ã¦ãã¾ããã
ããã§ãã¤ãã©ã¤ã³ã¯ä¸ã¤ã®AWSã¢ã«ã¦ã³ãã«éç´ããããããåã¢ã«ã¦ã³ãã«é å¸ããæ¹éã§åè¨è¨ãã¦ãããã¨ã¨ãªãã¾ããããã®æ§ç¯ã«ããã£ã¦aws-cdkãæ¡ç¨ããã®ã§ãããæå³éãã«åããªãã¨ããããããContributeãã¦ä¿®æ£ããã¾ã§ã®è©±ãæ¸ãã¾ãã
ã¡ãªã¿ã«ä»¥åã®Terraformãªã½ã¼ã¹ã®ä½ãæ¹ã«ããããã«Finatextã§ã¯Infrastructure as Code(以ä¸IaC)ã«ã¯Terraformãæ¡ç¨ãã¦ãã¾ãããä»åæ°ãã«aws-cdkã使ã£ã¦ã¿ã¦ã®ææãæ¸ããã°ãã¨æãã¾ãã
ã¯ãã¹ã¢ã«ã¦ã³ãã®ãã¤ãã©ã¤ã³
åºæ¬æ§æã¨ãã¦ã¯
- GitHubãã½ã¼ã¹ãããã¤ãã¨ããCodeBuildã§S3ã«ã½ã¼ã¹ãæ ¼ç´
- CodePipelineä¸ã®Sourceã¹ãã¼ã¸ã«S3ã使ç¨
- Buildã¹ãã¼ã¸ã«ã¯CodeBuildã並åã§ä½¿ç¨ããtestãbuildãåã
- Deployã¹ãã¼ã¸ã§ã¯CodeBuildãECSãªã©ã使ç¨ãããµã¼ãã¹ã¢ã«ã¦ã³ãã«è¨å®ãããroleãassumeãã¦åã¢ã«ã¦ã³ãã«é
å¸ãã
çºçããåé¡
cdkã®v1.27.0ã§ã¯ä»¥ä¸ã®æç²ããé¨åã®ããã«EcsDeployActionã¯ecs.BaseServiceã¯ã©ã¹ãè¦æ±ãã¦ãã¾ãã
åç
§ã³ã¼ã
export interface EcsDeployActionProps extends codepipeline.CommonAwsActionProps {/**
* The ECS Service to deploy.
*/
readonly service: ecs.BaseService;
}
ããããã¨ECSãµã¼ãã¹ã®ä½æã¨ã¨ãã«CodePipelineä¸ã®DeployActionãæ§ç¯ããå¿ è¦ãããããµã³ãã«ã³ã¼ãã¨ãã¦ã¯ä»¥ä¸ã®ããã«ãªãã¾ãã
const stack = new cdk.Stack();
const taskDefinition = new ecs.FargateTaskDefinition(stack, âTaskDefinitionâ);
taskDefinition.addContainer(âMainContainerâ, {
image: ecs.ContainerImage.fromRegistry(âamazon/amazon-ecs-sampleâ),
});
const vpc = new ec2.Vpc(stack, âVPCâ);
const cluster = new ecs.Cluster(stack, âClusterâ, {
vpc,
});
const service = new ecs.FargateService(stack, âFargateServiceâ, {
cluster,
taskDefinition,
});
const deployerRole = iam.Role.fromRoleArn(this, âdeployerRoleâ, âdeployerArnâ, {
mutable: false, //ã¯ãã¹ã¢ã«ã¦ã³ãã®roleã«assumeããããå¿
è¦
});
const deployAction = new codepipeline_actions.EcsDeployAction({
actionName: âDeployActionâ,
service: service,
role: deployerRole,
});
ããããä¸ã§èª¬æããããã«åã¢ã«ã¦ã³ãä¸ã®ECSãµã¼ãã¹ã¯cdkã®å¤ã§æ§ç¯ãã¦ãããæ¢åãªã½ã¼ã¹ãåç §ããå½¢ã§EcsDeployActionãä½ããå¿ è¦ãããã¾ããã
ããã§ãã®PRã§BaseServiceã¯ã©ã¹ã§ã¯ãªãã¦ãIBaseServiceã¤ã³ã¿ã¼ãã§ã¤ã¹ã«ä¾åãããããã«ãã¦ä»¥ä¸ã®ãããªå½¢ã§æ¸ããã¨ãã§ããããã«ãªãã¾ããã
v1.28.0ããå©ç¨å¯è½ã¨ãªã£ã¦ãã¾ãã
const stack = new cdk.Stack();
const clsuterName = âmy-clusterâ;
const serviceName = âmy-serviceâ;
//fromClusterAttributesã§å¿
è¦ãªã ãã§å©ç¨ããªãã®ã§dummy
const vpc = ec2.Vpc.fromVpcAttributes(stack, `VPC`, {
vpcId: âdummyâ,
availabilityZones: [âaâ, âbâ, âcâ]
});
//Ec2Serviceã§ãFargateServiceã§ãã©ã¡ãã§ãOK
const service = ecs.Ec2Service.fromEc2ServiceAttributes(stack, `EcsService`, {
serviceName: serviceName,
cluster: ecs.Cluster.fromClusterAttributes(stack, `Cluster`, {
vpc,
securityGroups: [],
clusterName: clsuterName,
}),
});
const deployerRole = iam.Role.fromRoleArn(this, âdeployerRoleâ, âdeployerArnâ, {
mutable: false, //ã¯ãã¹ã¢ã«ã¦ã³ãã®roleã«assumeããããå¿
è¦
});
const deployAction = new codepipeline_actions.EcsDeployAction({
actionName: âDeployActionâ,
service: service,
role: deployerRole,
});
VPCã¨ããEC2ã§ãFargeteã§ãã©ã£ã¡ã®Serviceã§ãè¯ãã¨ãã¨ããã¡ãã£ã¨å¾®å¦ãªã¨ããã¯æ®ã£ã¦ãã¾ãããå½åã®ç®çã¯éæã§ãã¾ãããï¼ããã®ã¨ããã¯PRãããã£ã³ã¹ããããï¼ï¼
å人çã«ä¸çªããã©ãã£ãã®ã¯cdkããããã?ã·ã¢ãã«ã®ãã¼ã ã§éçºãã¦ãã¦æå·®ã-16æéãã¤ã¾ãæ¥æ¬æéã®æ·±å¤2æã«ã·ã¢ãã«ã¯æ10æãªã®ã§ã¬ãã¥ã¼ã®å¾å¾©ãç¶ãã¨ãã¯çæ´»ãªãºã ãå´©ãã¦ãã¾ãã¨ãã§ããç¬
æ¥æ¬ã§åãã¦ãã¦OSSã«é¢ããéã®éå£ã¨ãã¦ã¯æå·®ãä¸çªå¤§ããã®ããªã¨æã£ã¦ãã¾ãã
å¥è§£
ããã¾ã§cdkã«æ¹ä¿®ãå
¥ãã¦è§£æ±ºããã¨ããæ¹åã§é²ãã¦ãã¾ããããaws-cdkãæ¥é 使ã£ã¦ããæ¹ã¯æã£ã¦ãããã¨ãããããããã¾ããã
cdkã®æçµçãªçæç©ã¯ããã¾ã§CloudFormationã®ymlã§ãããã¤ã³ã¿ã¼ãã§ã¤ã¹ãæºããããã«èªåã§ã¯ã©ã¹ãä½ã£ã¦ãªã½ã¼ã¹ãä½ããã¨ãã§ãã¾ãã
ä¾ãã°ä»¥ä¸ã®ãããªã¯ã©ã¹ãä½ããã¨ã§æ¢åã®ECSãµã¼ãã¹ã使ã£ãDeployActionãæ§ç¯ã§ãã¾ãã
interface MyEcsDeployActionProps extends codepipeline.CommonAwsActionProps {
readonly input: codepipeline.Artifact;
readonly serviceName: string;
readonly clusterName: string;
}class MyEcsDeployAction implements codepipeline.IAction {
public readonly actionProperties: codepipeline.ActionProperties;
private readonly props: MyEcsDeployActionProps;constructor(props: MyEcsDeployActionProps) {
this.actionProperties = {
â¦props,
category: codepipeline.ActionCategory.DEPLOY,
provider: âECSâ,
artifactBounds: { minInputs: 1, maxInputs: 1, minOutputs: 0, maxOutputs: 0 },
inputs: [props.input],
role: props.role
};this.props = props;
}public bind(_scope: cdk.Construct, _stage: codepipeline.IStage, options: codepipeline.ActionBindOptions):
codepipeline.ActionConfig {
return {
configuration: {
ClusterName: this.props.clusterName,
ServiceName: this.props.serviceName,
},
};
}public onStateChange(name: string, target?: events.IRuleTarget, options?: events.RuleProps): events.Rule {
throw new Error(âMethod not implemented.â);
}
}
ãã®ããããTerraformãCloudFormationã¨ã¯éãã¨ããã§ãã使ãå¿
è¦ã®ãããªã½ã¼ã¹ãTerraformã§å¯¾å¿ããã¦ãªããã°PRãéãã°è¯ããã¨ããæèåæ¢ã«é¥ã£ã¦ããåã«ã¨ã£ã¦ã¯æ¦æ
ãèµ°ãã¾ããã
ãã ãã®10ç§å¾ãããã«ãã§ãçµå±ã¯CloudFormationããµãã¼ããã¦ãªãã¨ã ãããã¨æ°ã¥ãã¾ããã
ä»å¾ã®èª²é¡
- ä¸ã¤ã®ã¢ã«ã¦ã³ãã«AWS CodePipelineãªã©åãã¿ã¤ãã®ãªã½ã¼ã¹ãä½ã£ã¦ãããããªãããã®å¶ç´ã¯æ°ã«ããå¿ è¦ããããå ¬å¼è³æ
- CodePipelineã®Sourceã¹ãã¼ã¸ã®GitHubã®ããªã¬ã¼ãä¸ååãªããCodeBuildãå©ç¨ãã¦ãããCodePipelineã®Sourceã¹ãã¼ã¸ã®GitHubã®ããªã¬ã¼ãä¸ååãªããCodeBuildãå©ç¨ãã¦ãã
IaCã®ææ
ã¾ãcdkã使ã£ã¦ã¿ã¦ã®ææ³ã¨ãã¦ã¯ãããªãAWSãææ¡ãã¦ããä¸ç´è
åãã¨ããå°è±¡ã§ãããããä¸ã«ãããµã³ãã«ã§ã¯ã«ãã¼ã§ããªããã®ãcdkã§ä½ãã¨ãªãã¨ãã¾ãåæã¨ãã¦CloudFormationã®ymlã¯èªããå¿
è¦ããããã`cdk synth`ãªã©ã§åãåºããymlãæå¾
ãã¦ãããã®ã¨ç°ãªãã¨ãã¯cdkã®ãªãªã¸ãã«ã½ã¼ã¹ã調ã¹ãå¿
è¦ãããã¾ãã
ããã¦ããã®2ã¤ã®å¿
è¦ã¨ãããã¹ãã«ãé åã¨ãã¦ã¯ããããé ããã®ãªã®ããªãã¨ããå°è±¡ã§ãã
ã¡ããã©å æ¥ã«ã¤ãã¯ã®è¤åããã以ä¸ãã¤ã¼ãããã¦ãã¾ããã
ããããèµ·ç¹ã¨ãªã£ãã®ã¯ãã¡ãã®ããã°ããªã¨ãï¼ãã ansibleã ã£ãããå«ãã§ã®è©±ãªã®ã§å°ã話ã¯å¤ããï¼
æ½è±¡åãéãã«é¢ãã¦ã¯æ¦ãåæã§åèªèº«ã®ã¹ã¿ã³ã¹ã¯ä»¥ä¸ã§ãã
ãããcdkã¯å¾®å¦ãªã®ããã¨ããã¨ãããªãã¨ã¯ãªãã¨æã£ã¦ãã¾ãã
AWSã¨ãã¦ã¯ã¢ããªã±ã¼ã·ã§ã³ã¨ã³ã¸ãã¢ãAWSãµã¼ãã¹ãã©ãã©ã触ã£ã¦ã¢ããªã±ã¼ã·ã§ã³ãä½ã£ã¦ãã£ã¦ã»ãããã¨ããæå¾ ããã£ã¦TypeScriptãé¸æããã®ãã¨æãã¾ãã
ãã TypeScriptã ã¨HCLãããä½è¨ã«ã¢ã¸ã¥ã¼ã«åã»å ±éåã«å¾åãããããã§ä»åã®ã±ã¼ã¹ã®ãããªã¨ã³ã¸ãã¢å ¨å¡ã«IaCæ¸ãã¦ã»ãããã©ãããããã¨ã¯çµããããå®ãããã¨ããã¨ãã«ã¯ä¸ã¤ã®é¸æè¢ã«ã¯ãªã£ã¦ãããã¨æãã¾ãã
ãããã«
Finatextã°ã«ã¼ãã§ã¯ãä¸ç·ã«åãã¨ã³ã¸ãã¢ã仲éãåéãã¦ãã¾ãï¼
å¾æ¥ã®éèãã¸ãã¹ã«ç¸ãããªããæ°ããªéèãµã¼ãã¹ãéçºãããæ¹ã¯æ¯éãé£çµ¡ãã ããï¼ï¼ãå¾
ã¡ãã¦ã¾ãï¼
æ±äººä¸è¦§ã¯ãã¡ã
社å¡ã¤ã³ã¿ãã¥ã¼ã¯ãã¡ã