ã¯ããã« ããã«ã¡ã¯ ãã¢ãã ã§ããã¯ãšã³ãåšãã®éçºãè¡ã£ãŠãã rymiyamoto ã§ãã ãã¢ãã ã§ã¯ãããŸã§æ§æã AWS ã® EKS ã䜿ã£ãŠããŸãããã2 æã®åæ¬ã« ECS ã«ç§»è¡ããã®ã§ãã®å
容ã玹ä»ããŠãããŸãã æ¬å
容ã®ã¹ã©ã€ãverã¯ãã¡ãâ speakerdeck.com çµç·¯ ç§»è¡ã決æããã®ã¯æå€§ã®çç±ã¯ãçŸç¶ã®ã¡ã³ããŒã§ kubernetes(ä»¥äž k8s) ã®ãã¡ã³ããã³ã¹ããŠããã³ã¹ããé«ãããããã§ãã k8s èªäœãé«é »åºŠã«ã¢ããããŒããé²ãã§ãããæ¥ã
ã®æ¥åãé²ãããã®ãã£ããã¢ãããé£ãããããã¢ããããŒãããã®ã¯ EKS ã®ãµããŒããåããééã«ãªã£ãŠããŸãåŸæã«åã£ãŠããŸããã (倧äœå¹Ž 1 åãããã®ããŒã¹ã§ãã£ãŠããŸãã) 察å¿ãããããéãããŒãžã§ã³ã倧ããé£ãã§ããŸãããããªãªãŒã¹ããŒãã远ã£ãŠã¡ãããšã¢ããããŒããå®äºããã«ã¯ã ããã 1 ã¡ã³ã㌠1 ã¶æãããã¯ããã£ãŠããŸããŸãã ãããå·¥æ°ããã£ãããªãããŸã瀟å
ã®å¥ãããã¯ãã§ ECS ã®éçšå®çžŸããã£ãããšããã®ã§åãããããšãšãªããŸããã ç§»è¡ãŸã§ã®ããŒãããã åºæ¬çã«ã¯ EKS éšåã ECS ã«ä¹ãæããã«æ¢ããå
šäœçãªã¢ãŒããã¯ãã£ã®å€æŽã¯ããªãæ¹åã§é²ããŸããã çç±ãšããŠã¯è«žäºæ
ã«ããå¯Ÿå¿æéãããŸãåããªãã£ãããã§ãã å®éé²ããŠãã£ããšãã®ããŒããããã¯ä»¥äžã®ããã«ãªããŸãã AWS ã³ã³ãœãŒã«äžã§ ECS ç°å¢ãçšæ ECS ç°å¢ã® IaC å & CI/CD ã®æŽå ECS ç°å¢ã«åãæ¿ã æ¬çªç§»è¡ãç§»è¡ EKS ç°å¢ã®ç Žæ£ AWS ã³ã³ãœãŒã«äžã§ ECS ç°å¢ãçšæ ãŸã㯠ECS ã«ä¹ãæããŠã¢ããªã±ãŒã·ã§ã³ã¬ãã«ã®ã§ä¿®æ£ãå¿
èŠãã確èªããããã«ãDEV ç°å¢ã®ã³ã³ãœãŒã«äžããç°å¢ãæ§ç¯ããŠãããŸããã ã¯ã©ã¹ã¿ãŒã®äœæ API server ãã web çãã¿ã¹ã¯å®çŸ© ã¿ã¹ã¯å®çŸ©ãããšã« ECS ã®ãµãŒãã¹ã Fargate ã§äœæ ãããã«äŒŽã role ã policy ã®äœæ/å€æŽ ECS ç°å¢ã® IaC å & CI/CD ã®æŽå ã¢ããªã±ãŒã·ã§ã³åŽã®èª¿æŽãæžã¿æ¬¡ç¬¬ãterraform ã«ãããåæ ããŠãããŸãã ãã ECS ã®ã¿ã¹ã¯å®çŸ©ã¯ååã®çæç§»è¡ããããã®ãµãŒãã¹ã§ç°å¢å€æ°ãã³ã³ããã€ã¡ãŒãžã管çããããããããããã® repository ã§ json ãã¡ã€ã«ãšããŠç®¡çããããã«ãªããŸããã ã¿ã¹ã¯å®çŸ©(task-definition.json) { " taskDefinition ": { " containerDefinitions ": [ { " name ": " api-server ", " image ": " 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/api-server:develop ", " cpu ": 0 , " portMappings ": [ { " containerPort ": 1323 , " hostPort ": 1323 , " protocol ": " tcp " } ] , " essential ": true , " command ": [ " /bin/sh ", " -c ", " './run.sh' " ] , // èµ·åã³ãã³ããã¹ã¯ãªããããã®ã§ãããå®è¡ " linuxParameters ": { " initProcessEnabled ": true } , " environment ": [ // more... ] , " ulimits ": [ { " name ": " nofile ", " softLimit ": 1024 , " hardLimit ": 4096 } ] , " mountPoints ": [] , " volumesFrom ": [] , " secrets ": [ // more... ] , " logConfiguration ": { " logDriver ": " awslogs ", " options ": { " awslogs-create-group ": " true ", " awslogs-group ": " /ecs/api-server ", " awslogs-region ": " ap-northeast-1 ", " awslogs-stream-prefix ": " ecs " } } } ] , " family ": " api-server ", " taskRoleArn ": " arn:aws:iam::111111111111:role/server-ecs-task-role ", " executionRoleArn ": " arn:aws:iam::111111111111:role/ecsTaskExecutionRole ", " networkMode ": " awsvpc ", " volumes ": [] , " placementConstraints ": [] , " requiresCompatibilities ": [ " FARGATE " ] , " cpu ": " 256 ", " memory ": " 512 ", " runtimePlatform ": { " cpuArchitecture ": " X86_64 ", " operatingSystemFamily ": " LINUX " } , " tags ": [] } } ãµãŒãã¹é¢é£ ä»åã¯å¥ãããã¯ãã§ãéçšããŠãã ecs-deploy ãå©çšããŸããã (ãã¡ãã¯çŸåšã¡ã³ããã³ã¹ã¢ãŒãã§æ©èœè¿œå ã¯ãããŸãããä¿å®ã¯æ»ããªãé²ãã§ããããã§ã) å
çšã®ããŒãã§äœæããã¿ã¹ã¯å®çŸ©ã® json ãæž¡ãããšã§ç°¡åã«ãããã€ããããšãã§ããŸãã # ecs-deployã®çšæ curl -sL https://github.com/silinternational/ecs-deploy/archive/ 3 . 10 . 7 .tar.gz | tar zxvf - mv ecs-deploy-3. 10 . 7 ecs-deploy chmod +x ecs-deploy/ecs-deploy # éäžã§docker image äœæãECRãžã®ã¢ããããŒãçã®åŠç # çç¥... # ãµãŒãã¹ãžããã〠ecs-deploy/ecs-deploy --cluster ecs-cluster \ --task-definition-file task-definition.json \ --service-name api-server \ --region ap-northeast-1 \ --timeout 600 \ --image 111111111111 .dkr.ecr.ap-northeast-1.amazonaws.com/api-server:develop äœè«ã§ãã ecspresso ã®æ¡çšãèŠéã«ãããŸããããä»åã¯å¯Ÿå¿ã§ããæéãçã瀟å
ã§éçšå®çžŸãªãããæ¡çšã¯èŠéããšãªã£ãŠããŸãã ãããé¢é£ ãããŸã§ k8s äžã§ã¯å®æå®è¡ã cronjobãã·ã§ããå®è¡ã§ job ãçšããŠããããŸããããã® docker image ã¯å
šãŠãŸãšããŠããŸããã (ããããå¢ãããã³ã« image ã ECR ãžç»é²ããŠããã®ã¯é¢åãªã®ã§) ãã®ãããã®ãŸãŸ AWS CLI ã§äœæãããš CloudWatch ã®ãã°ã°ã«ãŒããã²ãšãŸãšãã«ãªãèŠã¥ãããªã£ãŠããŸã + ã·ã§ããå®è¡ã®æ¹æ³ãé¢åã«ãªã£ãŠããŸããŸãã ä»å㯠scheduled task ã管çããããã« ecschedule ã§åæ ããããã«ããŸãããçç±ãšããŠã¯ãã¹ã±ãžã¥ãŒã«ãoverride å«ã㊠yaml ã§ç®¡çå¯èœãªãšãããš run ã§ã®å³æå®è¡ã«ã察å¿ããŠããããã§ãã å
±éåã§ããéšå㯠yaml ã®ãã³ãã¬ãŒãåãããã®ã§ ytt ãæ¡çšããŠããŸãã æ§æã€ã¡ãŒãžãšããŠã¯ä»¥äžã®ããã«ãªããŸãã . âââ base-task-def.jsonïŒãã³ãã¬ãŒããšãªãã¿ã¹ã¯å®çŸ©ïŒ âââ config.yamlïŒecsscheduleã§äœ¿ãèšå®ãã¡ã€ã«ïŒ âââ tasksïŒåbatchã®èšå®ãã¡ã€ã«ïŒ âââ batch-hoge.yaml âââ batch-fuga.yaml âââ more... base-task-def.json { " executionRoleArn ": " arn:aws:iam::111111111111:role/ecsTaskExecutionRole ", " containerDefinitions ": [ { " logConfiguration ": { " logDriver ": " awslogs ", " options ": { " awslogs-group ": " /ecs/server-batch ", " awslogs-region ": " ap-northeast-1 ", " awslogs-stream-prefix ": $job_name } } , " entryPoint ": [] , " portMappings ": [] , " command ": [] , " cpu ": 0 , " environment ": [ // more... ] , " mountPoints ": [] , " secrets ": [ // more... ] , " volumesFrom ": [] , " image ": " 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/server-batch:develop ", " name ": " server-batch " } ] , " placementConstraints ": [] , " memory ": " 1024 ", " taskRoleArn ": " arn:aws:iam::111111111111:role/scheduled-task ", " family ": $job_name, " requiresCompatibilities ": [ " FARGATE " ] , " networkMode ": " awsvpc ", " runtimePlatform ": { " operatingSystemFamily ": " LINUX " } , " cpu ": " 512 ", " volumes ": [] } config.yaml #@ load("@ytt:data", "data") region : ap-northeast-1 cluster : ecs-cluster rules : #@ data.values.rules batch-hoge.yaml #@data/values --- rules : - name : batch-hoge scheduleExpression : cron(0 0 * * ? *) taskDefinition : batch-hoge containerOverrides : - name : server-batch command : - ./exec environment : # more... launch_type : FARGATE platform_version : LATEST network_configuration : aws_vpc_configuration : subnets : - subnet-hoge - subnet-fuga - subnet-foo security_groups : - sg-hoge assign_public_ip : DISABLED disabled : false ãã®æ§æã®ããšã« CI åŽã§ã¿ã¹ã¯å®çŸ©ãš scheduled task ã®ç»é²ãè¡ã£ãŠããŸãã # tasksé
äžã®batchãããšã«ã¿ã¹ã¯å®çŸ© for item in ` ls tasks` do job = `basename ${item} .yaml` new_task_definition = $( jq -n --argjson job_name " \" $job \" " -f " base-task-def.json " ) aws ecs register-task-definition --cli-input-json " $new_task_definition " done # yttã§ecscheduleã§åæ ãããããã®yamlçæ ytt -f " config.yaml " -f " tasks " --file-mark ' config.yaml:exclusive-for-output=true ' > " ecschedule.yaml " # çæããyamlãå
ã«åæ ecschedule -conf " ecschedule.yaml " apply -all ãŸãäœè«ã§ãããã®æ§æã®ãšãã·ã§ããå®è¡ã®éã¯ä»¥äžã®ããã«å®è¡ã§ããŸãã # ã·ã§ããå®è¡ãããã¿ã¹ã¯ item = " batch-hoge.yaml " job = `basename ${item} .yaml` # yttã§ecscheduleã§åæ ãããããã®yamlçæ ytt -f " config.yaml " -f " tasks/ ${job} " --file-mark ' config.yaml:exclusive-for-output=true ' > " ecschedule.yaml " # çæããyamlãå
ã«åæ ecschedule -conf " ecschedule.yaml " run -rule $job ECS ç°å¢ã«åãæ¿ã äžæ°ã«æ°ç°å¢ã«åãæ¿ããŠããã®ã¯ãäžæž¬ã®äºæ
ããã£ããšãã«å¯Ÿå¿ã倧å€ã«ãªãã®ã§ãRoute53 ã§æ°ç°å¢ãžå éãæ°æ¥ãããŠå°ããå¢ãããŠãããŸããã ãŸã batch 系㯠äºéã§èµ°ããªãããã« EKS åŽã忢ããç¶æ
ã§ã¹ã±ãžã¥ãŒã«ã¿ã¹ã¯ã active ã«å€æŽããŠåæ ãããŠããŸãã EKS ç°å¢ã®ç Žæ£ äžèŠã«ãªã£ã EKS åãã® CI/CD ãé¢é£ãã aws ãªãœãŒã¹ã®åé€ãé²ããŠãããŸããã äžæ°ã« terraform ã§é¢é£ãªãœãŒã¹ãåé€ããããšãããšãéœåäžäŸåãããšå¥ã®ãªãœãŒã¹ãŸã§åœ±é¿ããŠããŸããŸãã ãã®ããä¿¡é Œé¢ä¿ãèŠã€ã€å°éã«ã¢ãžã¥ãŒã«åé€ãé²ããŠãããŸããã ç§»è¡ããŠã¿ãŠ ããã£ããšãã k8s ã®é ã«æ¯ã¹ãŠãµãŒãã¹ããããã®æ§æãããã¥ãã§ã¹ãã§ç®¡çããããã¯ã·ã³ãã«ãªæ§é ã«ãªããŸããã ãŸãæå€§ã®èª²é¡ã§ãã£ã EKS ã®ã¢ããããŒãäœæ¥ããã®éæŸã§ãããµãŒãã¹éçºã«éããéãããšãã§ããããã«ãªã£ããšæããŸãã 倧å€ã ã£ãããš EKS on EC2 ã§éçšããŠãããã®ã ECS Fargate ã«å€ããããšã§å³å¯ã«ãªãœãŒã¹ã®ç®¡çãããªããšãããªãã®ã§ããããŸã§èŠããŠããªãã£ãã¡ã¢ãªãªãŒã¯ãèµ·ããŠããããšã«æ°ä»ããããŸããã (ãã®å¯Ÿå¿ã®è©±ã¯ä»¥äžã®èšäºã§ç޹ä»ããŠããŸã) tech.every.tv ãŸã k8s èªäœã掻çºãªã³ãã¥ããã£æ
ã«ããŒã«ãè±å¯ã§ããããECS 㯠AWS ã«çžããã圢ãšãªãã®ã§ããã¡ã¯ãã¹ã¿ã³ããŒããšåŒã¹ããããã€æ¹æ³ãèŠåœãããäœããšåµæå·¥å€«ãå¿
èŠãšãªã£ãŠããŸããŸããã æåŸã« äžéçã®éã®æµããè¡ã察å¿ãšãªã£ãŠããŸãããk8s ãæ¡çšããå Žåã¯ãµãŒãã¹ãšçµç¹ã®èŠæš¡æãæèããŠãããªããšåŸã
ã®ã¡ã³ããã³ã¹ãèŸããªã£ãŠããŸããŸãã ãã¡ãã k8s ãæ£ãã䜿ãããªãããšæ§ã
ãªæ©èœã®æ©æµãåãããã®ã§ãäœå¶çã«ã¡ãããšé¢åãèŠãããã©ããã倿ããŠãšãå
¥ããã®ã¯åé¡ãªããšæããŸãã EKS(k8s)ãš ECS ãã©ã£ã¡ã§ãããããè¿·ã£ãŠããæ¹ããåãããã« ECS ãžã®ç§»è¡ãæ€èšããŠããæ¹ã®æå©ãã«ãªãã°å¹žãã§ãã