ããã«ã¡ã¯
ãžã§ã³ãã³ã¹ãci / cdããã³kubernetesã«é¢ããHabréã®èšäºã¯ãã§ã«ããã€ããããŸãããããã§ã¯ãããã®æè¡ã®æ©èœã®åæã«éäžããã®ã§ã¯ãªããci / cdãã€ãã©ã€ã³ãæ§ç¯ããããã®æãåçŽãªæ§æã«éäžããŸãã
èªè ãdockerã®åºæ¬ãç解ããŠããããšãæå³ããŸããkubernetesã®ã€ã³ã¹ããŒã«ãšæ§æã®ãããã¯ã«ã€ããŠã¯è§ŠããŸããã ãã¹ãŠã®äŸã¯minikubeã§è¡šç€ºãããŸããã倧ããªå€æŽãªãã§EKSãGKEãªã©ã«ãé©çšã§ããŸãã
ç°å¢
次ã®ç°å¢ã䜿çšããããšããå§ãããŸãã
- ãã¹ã-æåå±éããã³ãã©ã³ããã¹ãçš
- ã¹ããŒãžã³ã°-ãã¹ã¿ãŒã«åé¡ããããã¹ãŠã®å€æŽãèªåçã«å±éãããç°å¢
- æ¬çª-å®éã®ãŠãŒã¶ãŒã䜿çšããç°å¢ãã¹ããŒãžã³ã°ã§ã®æäœæ§ã確èªããåŸã«ã®ã¿å€æŽãè¡ãããŸã
ç°å¢ã¯ãåãã¯ã©ã¹ã¿ãŒå ã®kubernetesåå空éã䜿çšããŠç·šæãããŸãã ãã®ã¢ãããŒãã¯ãæåã¯ã§ããã ãã·ã³ãã«ãã€é«éã§ãããæ¬ ç¹ããããŸããkubernetesã§ã¯åå空éãäºãã«å®å šã«åé¢ãããŠããŸããã
ãã®äŸã§ã¯ãååå空éã«ã¯ããã®ç°å¢ã®æ§æãšåãConfigMapã®ã»ããããããŸãã
apiVersion: v1 kind: Namespace metadata: name: production --- apiVersion: v1 kind: ConfigMap metadata: name: environment.properties namespace: production data: environment.properties: | env=production
ãã«ã
Helmã¯ãkubernetesã«ã€ã³ã¹ããŒã«ããããªãœãŒã¹ã®ç®¡çã«åœ¹ç«ã€ã¢ããªã±ãŒã·ã§ã³ã§ãã
ã€ã³ã¹ããŒã«æé ã¯ãã¡ãã«ãããŸã ã
éå§ããã«ã¯ãã¯ã©ã¹ã¿ãŒã§helmã䜿çšããããã«èããããããåæåããå¿
èŠããããŸãã
helm init
ãžã§ã³ãã³ã¹
Jenkinsã¯ããããžã§ã¯ããæ§ç¯ããããã®éåžžã«ã·ã³ãã«ã§æè»æ§ããã人æ°ã®ãããã©ãããã©ãŒã ãªã®ã§ã䜿çšããŸãã ä»ã®ç°å¢ããåé¢ããããã«ãå¥ã®ããŒã ã¹ããŒã¹ã«ã€ã³ã¹ããŒã«ãããŸãã å°æ¥çã«ãã«ã ã䜿çšããäºå®ãªã®ã§ãæ¢åã®ãªãŒãã³ãœãŒã¹ãã£ãŒãã䜿çšããŠJenkinsã®ã€ã³ã¹ããŒã«ãç°¡çŽ åããããšãã§ããŸãã
helm install --name jenkins --namespace jenkins -f jenkins/demo-values.yaml stable/jenkins
demo-values.yamlã«ã¯ãJenkinsããŒãžã§ã³ãã€ã³ã¹ããŒã«æžã¿ãã©ã°ã€ã³ã®ã»ããããã¡ã€ã³åãããã³ãã®ä»ã®æ§æãå«ãŸããŠããŸã
Master: Name: jenkins-master Image: "jenkins/jenkins" ImageTag: "2.163-slim" OverwriteConfig: true AdminUser: admin AdminPassword: admin InstallPlugins: - kubernetes:1.14.3 - workflow-aggregator:2.6 - workflow-job:2.31 - credentials-binding:1.17 - git:3.9.3 - greenballs:1.15 - google-login:1.4 - role-strategy:2.9.0 - locale:1.4 ServicePort: 8080 ServiceType: NodePort HostName: jenkins.192.168.99.100.nip.io Ingress: Path: / Agent: Enabled: true Image: "jenkins/jnlp-slave" ImageTag: "3.27-1" #autoadjust agent resources limits resources: requests: cpu: null memory: null limits: cpu: null memory: null #to allow jenkins create slave pods rbac: install: true
ãã®æ§æã§ã¯ããã°ã€ã³çšã®ãŠãŒã¶ãŒåãšãã¹ã¯ãŒããšããŠadmin / adminã䜿çšããåŸã§åæ§æã§ããŸãã å¯èœãªãªãã·ã§ã³ã®1ã€ã¯google SSOã§ãïŒããã«ã¯google-loginãã©ã°ã€ã³ãå¿ èŠã§ãããã®èšå®ã¯Jenkins> Manage Jenkins> Configure Global Security> Access Control> Security Realm> Login with Googleã«ãããŸãïŒã
Jenkinsã¯ãåã¢ã»ã³ããªã«å¯ŸããŠ1åéãã®ã¹ã¬ãŒããèªåçã«äœæããããã«ããã«æ§æãããŸãã ããã«ãããããŒã ã¯ã¢ã»ã³ããªã«ç¡æã®ãšãŒãžã§ã³ããæåŸ ããªããªããäŒæ¥ã¯å¿ èŠãªãµãŒããŒã®æ°ãç¯çŽã§ããããã«ãªããŸãã
ãŸããããã©ã«ãã§ãPersistenceVolumeã¯åèµ·åãŸãã¯æŽæ°æã«ãã€ãã©ã€ã³ãä¿åããããã«æ§æãããŠããŸãã
èªåå±éã¹ã¯ãªãããæ£ããæ©èœãããã«ã¯ãJenkinsã«cluster-adminæš©éãä»äžããŠãkubernetesã®ãªãœãŒã¹ã®ãªã¹ããååŸããŠæäœããå¿ èŠããããŸãã
kubectl create clusterrolebinding jenkins --clusterrole cluster-admin --serviceaccount=jenkins:default
å°æ¥çã«ã¯ãæ°ããããŒãžã§ã³ã®ãã©ã°ã€ã³ãèšå®å€æŽã®å Žåã«ããã«ã ã䜿çšããŠJenkinsãæŽæ°ã§ããŸãã
helm upgrade jenkins stable/jenkins -f jenkins/demo-values.yaml
ããã¯Jenkinsèªäœã®ã€ã³ã¿ãŒãã§ãŒã¹ãä»ããŠå®è¡ã§ããŸããããã«ã ã䜿çšãããšã以äžã䜿çšããŠä»¥åã®ãªããžã§ã³ã«ããŒã«ããã¯ããæ©äŒããããŸãã
helm history jenkins helm rollback jenkins ${revision}
ã¢ããªã±ãŒã·ã§ã³æ§ç¯
äŸãšããŠãæãåçŽãªã¹ããªã³ã°ããŒãã¢ããªã±ãŒã·ã§ã³ããã«ãããŠãããã€ããŸãã Jenkinsã§ãåæ§ã«ãã«ã ã䜿çšããŸãã
ã¢ã»ã³ããªã¯æ¬¡ã®é åºã§è¡ãããŸãã
- ãã§ãã¯ã¢ãŠã
- ç·šé
- åäœãã¹ã
- çµ±åãã¹ã
- ã¢ãŒãã£ãã¡ã¯ãã¢ã»ã³ããª
- Dockerã¬ãžã¹ããªã§ã®ã¢ãŒãã£ãã¡ã¯ãã®å±é
- ã¹ããŒãžã³ã°ãžã®ã¢ãŒãã£ãã¡ã¯ãã®å±éïŒãã¹ã¿ãŒãã©ã³ãã®ã¿ïŒ
ãã®ããã«ãç§ã¯Jenkinsãã¡ã€ã«ã䜿çšããŸã ã ç§ã®æèŠã§ã¯ãããã¯ãããžã§ã¯ãã¢ã»ã³ããªãæ§æããããã®éåžžã«æè»ãªïŒãã ããæ®å¿µãªãããæãç°¡åã§ã¯ãããŸããïŒæ¹æ³ã§ãã ãã®å©ç¹ã®1ã€ã¯ããããžã§ã¯ãèªäœã®ãªããžããªã«ãããžã§ã¯ãã¢ã»ã³ããªã®æ§æãä¿æã§ããããšã§ãã
ãã§ãã¯ã¢ãŠã
bitbucketãŸãã¯githubã®çµç¹ã®å ŽåãJenkinsfileã䜿çšããŠãªããžããªã®ååšãã¢ã«ãŠã³ãå šäœã§å®æçã«ã¹ãã£ã³ãããããã®ã¢ã»ã³ããªãèªåçã«äœæããããã«Jenkinsãæ§æã§ããŸãã Jenkinsã¯ãã¹ã¿ãŒãšãã©ã³ãã®äž¡æ¹ãåéããŸãã ãã«ãªã¯ãšã¹ãã¯å¥ã®ã¿ãã«è¡šç€ºãããŸãã ããç°¡åãªãªãã·ã§ã³ããããŸã-ãã¹ããããŠããå Žæã«é¢ä¿ãªããå¥åã®gitãªããžããªãè¿œå ããŸãã ãã®äŸã§ã¯ããŸãã«ãããè¡ããŸãã å¿ èŠãªã®ã¯ãJenkins> New item> Multibranch Pipelineã¡ãã¥ãŒã§ãã¢ã»ã³ããªåãéžæããgitãªããžããªããã€ã³ãããããšã§ãã
ç·šé
Jenkinsã¯ã¢ã»ã³ããªããšã«æ°ããããããäœæãããããmavenãŸãã¯åæ§ã®ã³ã¬ã¯ã¿ãŒã䜿çšããå ŽåãäŸåé¢ä¿ã¯æ¯åå床ããŠã³ããŒããããŸãã ãããåé¿ããã«ã¯ã.m2ãŸãã¯åæ§ã®ãã£ãã·ã¥ã«PersistenceVolumeãéžæãããããžã§ã¯ãããã«ããããããã«ããŠã³ãããŸãã
apiVersion: "v1" kind: "PersistentVolumeClaim" metadata: name: "repository" namespace: "jenkins" spec: accessModes: - ReadWriteMany resources: requests: storage: 10Gi
ç§ã®å Žåãããã«ãããã€ãã©ã€ã³ãçŽ4åãã1åã«é«éåã§ããŸããã
ããŒãžã§ãã³ã°
CI / CDãæ£åžžã«æ©èœããã«ã¯ãåãã«ãã«åºæã®ããŒãžã§ã³ãå¿ èŠã§ãã
éåžžã«è¯ããªãã·ã§ã³ã¯ã ã»ãã³ãã£ãã¯ããŒãžã§ã³ç®¡çã䜿çšããããšã§ãã ããã«ãããåŸæ¹äºææ§ãšéäºææ§ã®ããå€æŽã远跡ã§ããŸããããã®ãããªããŒãžã§ã³ç®¡çã¯èªååãããå°é£ã§ãã
ãã®äŸã§ã¯ãIDãšã³ãããã®æ¥ä»ããããŒãžã§ã³ãçæããŸãããã©ã³ãããã¹ã¿ãŒã§ãªãå Žåã¯ããã©ã³ãã®ååãçæããŸãã äŸïŒ 56e0fbdc-201802231623ãŸãã¯b3d3c143-201802231548-PR-18
ãã®ã¢ãããŒãã®å©ç¹ïŒ
- èªååã®å®¹æã
- ããŒãžã§ã³ãããœãŒã¹ã³ãŒããšãã®äœææéãååŸããã®ã¯ç°¡åã§ã
- èŠèŠçã«ã¯ãåè£ã®ãªãªãŒã¹ããŒãžã§ã³ïŒãŠã£ã¶ãŒãããïŒãŸãã¯å®éšçïŒãã©ã³ãããïŒãåºå¥ã§ããŸãã
ãããïŒ - ãã®ããŒãžã§ã³ã¯å£é ã§ã®ã³ãã¥ãã±ãŒã·ã§ã³ã§ã¯äœ¿ãã«ãã
- äºææ§ã®ãªãå€æŽããã£ããã©ããã¯æããã§ã¯ãããŸããã
dockerã€ã¡ãŒãžã¯åæã«è€æ°ã®ã¿ã°ãæã€ããšãã§ãããããã¢ãããŒããçµã¿åãããããšãã§ããŸãããã¹ãŠã®ãªãªãŒã¹ã¯çæãããããŒãžã§ã³ã䜿çšããæ¬çªã«è©²åœãããã®ã¯ã»ãã³ãã£ãã¯ããŒãžã§ã³ç®¡çã§è¿œå ïŒæåïŒã¿ã°ä»ããããŸãã ããã¯ãããã«è€éãªå®è£ ãšãã¢ããªã±ãŒã·ã§ã³ã衚瀺ããããŒãžã§ã³ã®ãããŸããã«é¢é£ããŠããŸãã
ã¢ãŒãã£ãã¡ã¯ã
ã¢ã»ã³ããªã®çµæã¯æ¬¡ã®ããã«ãªããŸãã
- Dockerã¬ãžã¹ããªããä¿åããã³ããŒããããã¢ããªã±ãŒã·ã§ã³ãå«ãdockerã€ã¡ãŒãžã ãã®äŸã§ã¯ãminikubeã®çµã¿èŸŒã¿ã¬ãžã¹ããªã䜿çšããŸããããã¯ãdockerããããŸãã¯AmazonïŒecrïŒãŸãã¯googleã®ãã©ã€ããŒãã¬ãžã¹ããªã«çœ®ãæããããšãã§ããŸãïŒwithCredentialsã³ã³ã¹ãã©ã¯ãã䜿çšããŠè³æ Œæ å ±ãæäŸããããšãå¿ããªãã§ãã ããïŒã
- ãã«ã ãã£ã¬ã¯ããªå ã®ã¢ããªã±ãŒã·ã§ã³ã®å±éã®èª¬æïŒå±éããµãŒãã¹ãªã©ïŒãå«ããã«ã ãã£ãŒãã çæ³çã«ã¯ãã¢ãŒãã£ãã¡ã¯ãã®å¥ã®ãªããžããªã«ä¿åããå¿ èŠããããŸãããç°¡çŽ åããããã«ãgitããå¿ èŠãªã³ãããããã§ãã¯ã¢ãŠãããŠäœ¿çšã§ããŸãã
ãžã§ã³ãã³ã¹ãã¡ã€ã«
ãã®çµæãã¢ããªã±ãŒã·ã§ã³ã¯æ¬¡ã®Jenkinsfileã䜿çšããŠæ§ç¯ãããŸãã
def branch def revision def registryIp pipeline { agent { kubernetes { label 'build-service-pod' defaultContainer 'jnlp' yaml """ apiVersion: v1 kind: Pod metadata: labels: job: build-service spec: containers: - name: maven image: maven:3.6.0-jdk-11-slim command: ["cat"] tty: true volumeMounts: - name: repository mountPath: /root/.m2/repository - name: docker image: docker:18.09.2 command: ["cat"] tty: true volumeMounts: - name: docker-sock mountPath: /var/run/docker.sock volumes: - name: repository persistentVolumeClaim: claimName: repository - name: docker-sock hostPath: path: /var/run/docker.sock """ } } options { skipDefaultCheckout true } stages { stage ('checkout') { steps { script { def repo = checkout scm revision = sh(script: 'git log -1 --format=\'%h.%ad\' --date=format:%Y%m%d-%H%M | cat', returnStdout: true).trim() branch = repo.GIT_BRANCH.take(20).replaceAll('/', '_') if (branch != 'master') { revision += "-${branch}" } sh "echo 'Building revision: ${revision}'" } } } stage ('compile') { steps { container('maven') { sh 'mvn clean compile test-compile' } } } stage ('unit test') { steps { container('maven') { sh 'mvn test' } } } stage ('integration test') { steps { container ('maven') { sh 'mvn verify' } } } stage ('build artifact') { steps { container('maven') { sh "mvn package -Dmaven.test.skip -Drevision=${revision}" } container('docker') { script { registryIp = sh(script: 'getent hosts registry.kube-system | awk \'{ print $1 ; exit }\'', returnStdout: true).trim() sh "docker build . -t ${registryIp}/demo/app:${revision} --build-arg REVISION=${revision}" } } } } stage ('publish artifact') { when { expression { branch == 'master' } } steps { container('docker') { sh "docker push ${registryIp}/demo/app:${revision}" } } } } }
ã¢ããªã±ãŒã·ã§ã³ã©ã€ããµã€ã¯ã«ç®¡ççšã®è¿œå ã®Jenkinsãã€ãã©ã€ã³
ãªããžããªã次ã®ããã«ç·šæãããŠãããšä»®å®ããŸãã
- Dockerã€ã¡ãŒãžã®åœ¢åŒã§åå¥ã®ã¢ããªã±ãŒã·ã§ã³ãå«ã
- helmãã£ã¬ã¯ããªã«ããhelmãã¡ã€ã«ã䜿çšããŠå±éã§ããŸã
- åãã¢ãããŒãã䜿çšããŠããŒãžã§ã³ç®¡çããããã«ã ãã£ãŒãã«ãªããžã§ã³ãèšå®ããããã®helm / setVersion.shãã¡ã€ã«ããããŸã
ãã®åŸãã¢ããªã±ãŒã·ã§ã³ã®ã©ã€ããµã€ã¯ã«ã管çããããã«ãããã€ãã®Jenkinsfileãã€ãã©ã€ã³ãæ§ç¯ã§ããŸãã
- ããããç°å¢ãžã®å±é
- ç°å¢ããã®åé€
- çç£ã®ã¹ããŒãžã³ã°ã§ä¿é²ãã
- åã®ããŒãžã§ã³ãžã®ããŒã«ããã¯
åãããžã§ã¯ãã®Jenkinsfileã«ããã¹ã¿ãŒãã©ã³ããæ£åžžã«ã³ã³ãã€ã«ããããã³ã«ããŸãã¯ãããã€ãã©ã³ãããã¹ãç°å¢ãæ瀺çã«èŠæ±ãããã³ã«å®è¡ããããããã€ãã€ãã©ã€ã³ã³ãŒã«ãè¿œå ã§ããŸãã
... stage ('deploy to env') { when { expression { branch == 'master' || params.DEPLOY_BRANCH_TO_TST } } steps { build job: './../Deploy', parameters: [ [$class: 'StringParameterValue', name: 'GIT_REPO', value: 'habr-demo-app'], [$class: 'StringParameterValue', name: 'VERSION', value: revision], [$class: 'StringParameterValue', name: 'ENV', value: branch == 'master' ? 'staging' : 'test'] ], wait: false } } ...
ããã§ã¯ããã¹ãŠã®æé ãå«ãJenkinsfileãèŠã€ããããšãã§ããŸãã
ãããã£ãŠãéžæãããã¹ããŸãã¯æŠéç°å¢ã§ç¶ç¶çãªå±éãæ§ç¯ãããžã§ã³ãã³ã¹ãŸãã¯ãã®ã¡ãŒã«/ã¹ã©ãã¯/ãªã©ã®éç¥ã䜿çšããŠãã©ã®ã¢ããªã±ãŒã·ã§ã³ãã©ã®ããŒãžã§ã³ã誰ããã€ãã©ãã§ã€ã³ã¹ããŒã«ãããããç£æ»ããããšãã§ããŸãã
ãããã«
Jenkinsfileãšhelmã䜿çšãããšãã¢ããªã±ãŒã·ã§ã³çšã«ci / cdãç°¡åã«æ§ç¯ã§ããŸãã ãã®æ¹æ³ã¯ãæè¿kubernetesã®äœ¿çšãéå§ãããã®ãããªæ©èœãããã«äœ¿çšã§ãããµãŒãã¹ãïŒçç±ã«é¢ä¿ãªãïŒäœ¿çšã§ããªãå°èŠæš¡ãªããŒã ã«æãé¢é£ããå ŽåããããŸãã
ããã§ã¯ãã¢ããªã±ãŒã·ã§ã³ã©ã€ããµã€ã¯ã«ã管çããããã®ç°å¢ãJenkinsãããã³ãã€ãã©ã€ã³ã®æ§æäŸãšãJenkinsfileã䜿çšãããµã³ãã«ã¢ããªã±ãŒã·ã§ã³ãèŠã€ããããšãã§ããŸãã