先日のAWS障害で管理していたECSに多少の影響が出たので、そのタイミングで敷設していたJenkinsの構成を改めて整理しました。今回は課題解決というより、既に稼働していたシステム構成の振り返りを行いました。
というわけで、モダンなJenkins2系をAWS CDKで敷設してみました。
大方の構成は「nabinno/jenkins-cdk-on-ec2」のシステム構成図をご覧下さい。元ネタはaws-sampleになりますが、今回はAWS FargateではなくAmazon ECSを採用し、CDKはTypeScriptで実装しています。
使用技術スタック
CDKによるJenkinsの敷設はGitHubレポジトリーを見ていただくとして、ここではCDKのコード上の注意点を2点ほど共有しておきます。
CDKで各リソース名を明示しないとCloudFormation(CFn)独特の命名規則でリソースが敷設されます。インフラ担当が自分一人の場合は良いですが、インフラ担当を増員する際は、他のIaCツールの運用方針とバッティングする等、後で足かせになるので命名規則にのっとりリソース名を付けていくようにしましょう。
命名規則は「クラスメソッドさんの記事」を参考に決めるのが定番のようです。下記例になります。
AWSリソース | 命名規則 |
---|---|
ELB | {sysname}-{env}-alb/clb |
TargetGroup | {sysname}-{env}-tg |
EC2 | {sysname}-{env}-{type} |
SecurityGroup | {sysname}-{env}-{type}-sg |
CDKでリソース名を明示するには次のいずれかの方法で対応します。
下記コードでは暗黙的に生成されていたSecurity Groupを明示的に作成している様子等が見て取れます。
// ECS: Service
const serviceSecGrp = new ec2.SecurityGroup(this, "JenkinsMasterServiceSecGrp", {
securityGroupName: "jenkins-production-master-sg",
vpc: network.vpc,
allowAllOutbound: true,
});
serviceSecGrp.addIngressRule(worker.workerSecurityGroup, ec2.Port.tcp(50000), "from JenkinsWorkerSecurityGroup 50000");
serviceSecGrp.addIngressRule(worker.workerSecurityGroup, ec2.Port.tcp(8080), "from JenkinsWorkerSecurityGroup 8080");
const jenkinsMasterService = new ecs.Ec2Service(this, "EC2MasterService", {
serviceName: 'jenkins-production-master-svc',
taskDefinition: jenkinsMasterTask,
cloudMapOptions: { name: "master", dnsRecordType: sd.DnsRecordType.A },
desiredCount: 1,
minHealthyPercent: 0,
maxHealthyPercent: 100,
enableECSManagedTags: true,
cluster: ecsCluster.cluster,
securityGroups: [serviceSecGrp]
});
なお、リソース名の明示化について、もちろんCDKのクラスによっては暗黙的なリソースを含んでおり当該リソースに名前を付けることが出来ないケースはあります。今回のケースで言うと、例えば、ECSクラスター(EC2)のIAM RoleやSecurity Group。その場合は、インフラのCDK運用方針としてドキュメントに残しておく等しておくと良いでしょう。
ネットワーク、ストレージ関連のリソースを扱う場合、削除されるとリソース構成が破綻する可能性があるのでcdk.RemovablePolicy.RETAIN
、CFnの言うところの "DeletionPolicy": "Retain"
をつけましょう。今回はEFSがその対象になります。
const efsFilesystem = new efs.CfnFileSystem(this, "EFSBackend");
efsFilesystem.applyRemovalPolicy(cdk.RemovalPolicy.RETAIN);
個人的にはRETAIN
をつけるとcdk destroy
cdk deploy
を気軽に行えなくなるので、RETAIN
をつけるならCDK/CFnからはARNで参照する程度に抑えた方が良いと思っています。
CDKでJenkinsを敷設した終わったらJenkinsの設定を行いましょう。
昔と違って今のJenkinsは下記プラグインがあれば十分運用できます。
ざっと説明するとgithub-oauth
でGitHub認証させ、role-strategy
でロールごとの権限付与を行い、configuration-as-code
でそれらの管理設定をコード化します。configuration-as-code
は素晴らしく設定情報をコード化することでdockerイメージに当該設定情報を反映させることが出来ます。また、blueocean
はモダンなインターフェイスでジョブ実行します。こちらは次のセクションで詳細を説明します。
なお、プラグイン管理はIaC化でき下記のようにdockerイメージに反映できます。
$ cat plugins.txt
role-strategy:3.1
github-oauth:0.33
thinBackup:1.10
git:4.6.0
authorize-project:1.3.0
configuration-as-code:1.47
blueocean:1.24.4
$ cat Dockerfile
[...]
COPY plugins.txt /usr/share/jenkins/ref/plugins.txt
RUN /usr/local/bin/install-plugins.sh < /usr/share/jenkins/ref/plugins.txt
[...]
いよいよJenkinsでジョブの管理設定を行います。具体的には下記手順で実施します。手順が完了すると作ったブランチ分だけJenkinsにジョブが追加されます、とても簡単です。
Jenkinsfile
を配置Jenkinsfile
の作成方法は「ユーザーハンドブック」にありますが、下記例のように直感的に記述することが出来ます。環境変数は「Jenkins - {{レポジトリ}} - 認証情報 - Stores scoped to {{レポジトリ}} - global - Add credential」から追加します。
pipeline {
agent any
stages {
stage('Show env') {
steps {
sh '''mysql --version
ls -al bin
env | sort'''
}
}
stage('Run script') {
steps {
git(url: 'https://github.com/nabinno/jenkins-jobs', branch: 'master', credentialsId: 'github')
sh '''git diff sync-db-from-staging-to-integration | patch -p1 -R -f
bin/sync_db_from_staging_to_integration'''
}
}
}
environment {
STAG_DB_DATABASE = credentials('STAG_DB_DATABASE')
STAG_DB_HOSTNAME = credentials('STAG_DB_HOSTNAME')
STAG_DB_PASSWORD = credentials('STAG_DB_PASSWORD')
STAG_DB_USERNAME = credentials('STAG_DB_USERNAME')
INTEG_DB_HOSTNAME = credentials('INTEG_DB_HOSTNAME')
INTEG_DB_PASSWORD = credentials('INTEG_DB_PASSWORD')
INTEG_DB_USERNAME = credentials('INTEG_DB_USERNAME')
INTEG_DB_DATABASE = credentials('INTEG_DB_USERNAME')
}
}
今回の振り返りで、2点気づきを得られました。CDKのリソース名の扱いに困っていたのですが、どうにか制御できそうなのでまたしばらくは付き合っていくことになりそうです。
テクノロジーの進化は、絶え間ない変化の中で私たちの日常を塗り替えてきました。時には経済的な危機が、新たな可能性を切り拓く契機となることもあります。そこで、過去のリセッション期に生まれたテクノロジーの足
ATKerneyの課題解決パターン は、課題の本質を見極め、効果的な戦略的構造化を通じて解決策を導き出す手法にフォーカスしています。この冒険の旅は、解決者と協力者たちが心を一つにし、課題に立ち向かう様
私はいわゆる就職氷河期世代です。周囲から時折漏れ聞こえる不平のような言葉がありますが、それを単なる不平として片付けるのはもったいない気がします。できれば、その中に新しい視点を見つけ、次のチャンスへ繋げ