コヌドずしおのむンフラストラクチャのリリヌスサむクル

むンタヌネットでは、むンフラストラクチャに関する倚くの蚘事をコヌド、SaltStack、Kitchen-CIナヌティリティなどずしお芋぀けるこずができたすが、さたざたな皮類のIaCの䟋を芋おいないので、通垞はVCSのブランチに分割されたコヌドのみです。環境のタむプの名前、たずえばdev / intはタグを䜿甚しおも可胜です。たた、原則ずしお、本栌的な構成開発サむクルに぀いお話す必芁はありたせん。 いずれにせよ、この状況に粟通しおいる䌁業では、蚘事は芋぀かりたせんでした。

倚分それは理解できる-党䜓的なアゞャむルず「䞀床だけの生産」。

この蚘事で状況を修正しようずしたす。







短い仕事の説明



この蚘事では、プラットフォヌムのプロゞェクトのむンフラストラクチャ゜リュヌションの構成ず管理の分野での゜リュヌションに぀いお説明したす。この゜リュヌションは、分析ナニットを陀く20の異なるコンポヌネントで構成され、合蚈70の「サヌバヌナニット」を備えおいたす。







正盎に蚀うず、特にこれらすべおが自動的に制埡および構成されおいる堎合、それほど倚くはありたせん。 倧芏暡なシステムに぀いおは説明できたすが、正盎なずころ、ほが同じです。それは、より倚くのむンスタンスに広がっおいるだけで、「䌁業」は束葉杖のように読みたす。

培地の䟋は、皮子甚です。







説明したプラットフォヌムは、SaltStackモゞュヌルによっお完党に管理され、SaltStackモゞュヌルによっお新しいむンスタンスを自然に䜜成および起動したす。 もちろん、各プラットフォヌムサヌビスを蚭定する必芁がありたすが、システムサヌビスの蚭定を忘れないでください。







そのため、たずえば、最も䞀般的なWebサヌバヌの構成には、nginx / httpdおよびサむト自䜓の構成だけでなく、システムサヌビスも含たれたす。









サむトのDNSレコヌド、蚌明曞の発行ず再発行を忘れないでください。

各サヌビスの構成を個別に説明するず、コピヌアンドペヌストするだけでも倢䞭になりたす。







幞いなこずに、SaltStackは、他のほずんどの構成管理システムず同様に、Formulasず呌ばれる再珟可胜な構成ブロックを備えおいたす。 ただし、匏をコピヌしたり、リポゞトリから盎接プルしたりするこずは、䜕らかのタグたたは特別なリリヌスブランチからであっおも、安定化ず再珟性の芳点からは完党に正しくありたせん-タグを曞き換え、ブランチを曎新し、チェックおよび怜蚌できたす難しすぎたす リビゞョンに基づいた数匏間の察応䟝存関係のリストを維持する必芁がありたす。 このために、モゞュヌルず䟝存関係をバヌゞョン管理するプロセスはかなり前に発明されたした。 はい、もちろん、リビゞョンずずもにバヌゞョンの䟝存関係を远加できたすが、VCSはファむルの倉曎履歎を維持するために開発されたものであり、リリヌスアヌティファクトを修正するためではありたせん。







顧客の環境で数匏を䜿甚する必芁がある状況を忘れないでください。顧客の環境から䌚瀟のリポゞトリサヌバヌぞのアクセスを開くこずは、それをやや安党にせず、バむナリアヌティファクトぞのアクセスを提䟛する方がはるかに安党です。

SaltStackは、バヌゞョン付きのバむナリパッケヌゞを操䜜できるコンポヌネントを提䟛したす。







このコンポヌネントは、 SaltStack Packet Managerたたは略しおSPMず呌ばれたす。 本質的に、結果のパッケヌゞはtarであり、bzipによっおメタ情報を圧瞮されおおり、 FORMULAファむルが責任を負いたす。 リポゞトリを維持するためには、リポゞトリ内に保存されたすべおのアヌティファクトが存圚する堎合に生成されるメタ情報ファむルも生成する必芁があるこずに泚意しおください。原則はYumリポゞトリず同じです。 SPMには、この情報を含むメタデヌタファむルをたずめお、匏の䟝存関係のバヌゞョンを指定するにもかかわらず、リポゞトリで䜿甚可胜な匏を䞀芧衚瀺できないなど、SPMにいく぀かの欠点がありたすが、これはSPM自䜓の若さによるものです。バヌゞョン2016.3でメモリが倉曎されない堎合。







リリヌスオブゞェクト



ビゞネスに取り掛かりたしょう。 これを行うには、知られおいないGitbucketサヌビスの構成を怜蚎しおください-Scalaで曞かれたオヌプン゜ヌスのgitリポゞトリ管理システムは、かなり良いAPI、プラグむンシステム、玠敵で䟿利なWebむンタヌフェむスを備え、Bitbucket、GitHub、GitLabなどのマスタヌず完党に比范したすCIなしおよびBeanstalkず比范しお特に豪華です。







だから、私が蚀ったように、それはscalaで曞かれおおり、Webアプリケヌションなので、少なくずも次の構成が必芁です-java、tomcat、nginx。

DockerホストでKitchen-ClプロバむダヌずしおKitchen-CIを䜿甚しおテストしたす。







構成のあるディレクトリの構造を考慮しおみたしょう。







gitbucket-formula |-- gitbucket | |-- frontend | | |-- templates | | | |-- nginx-http.conf | | | |-- nginx-https.conf | | | `-- upstream.conf | | `-- init.sls | |-- plugins | | `-- init.sls | |-- templates | | |-- database.conf | | `-- gitbucket.conf | |-- init.sls | `-- settings.jinja |-- test | `-- integration | |-- fe | | `-- serverspec | | `-- frontend_spec.rb | |-- fe-ssl | | `-- serverspec | | `-- frontend_ssl_spec.rb | |-- gitbucket | | `-- serverspec | | `-- gitbucket_spec.rb | `-- helpers | `-- serverspec | |-- fe_shared_spec.rb | |-- fe_ssl_shared_spec.rb | `-- gitbucket_shared_spec.rb |-- .editorconfig |-- .gitattributes |-- .gitconfig |-- .gitignore |-- .kitchen.yml |-- pillar.example |-- FORMULA `-- README.md
      
      





ご芧のように、匏にはメむンのサヌビス構成パラメヌタヌだけでなく、テストディレクトリのserverspecに蚘述されたテスト、FORMULAメタ情報ファむル、キッチンの構成蚘述子、およびgitリポゞトリヌ構成サヌビスファむルも含たれおいたす。







珟時点では、.kitchen.ymlファむルに興味がありたす。







 --- driver: name: docker use_sudo: false require_chef_omnibus: false socket: tcp://dckhub.platops.org:2375 volume: /sys/fs/cgroup cap_add: - SYS_ADMIN provisioner: name: salt_solo formula: gitbucket salt_bootstrap_options: 'stable 2016.11' dependencies: - path: ../tomcat-formula name: tomcat - path: ../oracle-jdk-formula name: oracle-jdk - path: ../nginx-formula name: nginx state_top: base: '*': - gitbucket pillars: top.sls: base: '*': - gitbucket gitbucket.sls: tomcat: instance: name: 'gitbucket' connport: '8080' sslport: '8443' xms: '512M' xmx: '1G' mdmsize: '256M' frontend.sls: gitbucket: frontend: enabled: False ssl: enabled: False external: False crt: | -----BEGIN CERTIFICATE----- C    ssl  localhost -----END CERTIFICATE----- key: | -----BEGIN RSA PRIVATE KEY-----    -----END RSA PRIVATE KEY----- platforms: - name: debian driver_config: image: debian:8 run_command: /sbin/init provision_command: - apt-get install -y --no-install-recommends wget curl tar mc iproute apt-utils apt-transport-https locales - localedef --no-archive -c -i en_US -f UTF-8 en_US.UTF-8 && localedef --no-archive -c -i ru_RU -f UTF-8 ru_RU.UTF-8 - name: centos driver_config: image: dckreg.platops.org/centos-systemd:7.3.1611 run_command: /sbin/init provision_command: - yum install -y -q wget curl tar mc iproute - localedef --no-archive -c -i en_US -f UTF-8 en_US.UTF-8 && localedef --no-archive -c -i ru_RU -f UTF-8 ru_RU.UTF-8 - sed -i -r 's/^(.*pam_nologin.so)/#\1/' /etc/pam.d/sshd - sed -i 's/tsflags=nodocs//g' /etc/yum.conf suites: - name: gitbucket - name: fe provisioner: pillars: top.sls: base: '*': - gitbucket - frontend frontend.sls: gitbucket: frontend: enabled: True - name: fe-ssl provisioner: pillars: top.sls: base: '*': - gitbucket - frontend frontend.sls: gitbucket: frontend: enabled: True url: localhost ssl: enabled: True
      
      





Driverセクションでは、Dockerホストを操䜜するためのパラメヌタヌを指定したす。ロヌカルアドレスも指定できたす。たた、他のドラむバヌ、たずえばvagrant 、 ec2などを䜿甚できたす。

Provisionerセクションは、SaltStackが構成をロヌルするために必芁な構成を担圓したす。ここで、この匏の䞊蚘の䟝存関係、柱を介しお送信されるサヌビスの構成をむンストヌルしたす。

プラットフォヌムセクションでは、テストが実行されるオペレヌティングシステムずしお読み取るプラットフォヌムを定矩したす。

最埌に、スむヌト、このセクションでは、䞊蚘のプラットフォヌムでテストする構成のタむプを指定したす。 Kitchenの指定された蚘述子では、3皮類のテストが構成されおいたす。









合蚈で、OSごずに3぀の構成がテストされたす-Debian JessieおよびCentOS 7。







ディレクトリビュヌからわかるように、テストスむヌトがありたす-gitbucket、fe、fe-sslによる分離を含むテストフォルダヌがありたす。ヘルパヌフォルダヌにも泚意を払っおください。テストの皮類ごずにshared_examplesが含たれ、同じテストを蚘述しないようになっおいたす。







䟝存関係



SaltStackの柱構成ずブヌトストラップパラメヌタヌに加えお、Provisionerセクションに泚目したしょう。このセクションには、構成プロセス䞭の盞察パスたたは絶察パスで利甚できるこの構成の䟝存関係に関する情報も含たれおいたす。 ご芧のずおり、このサヌビスのテストに盎接関係する構成のみがリストされおいたす。

もちろん、むンスタンスの構成を完党にカバヌするために䞊蚘の9぀のシステムサヌビスを远加できたすが、たず、そのようなテストには数時間かかりたす。たずえば、2぀のOSファミリに必芁なすべおのプラグむンをむンストヌルするJenkinsの匏では、それぞれ3぀の構成で玄1時間かかりたす-第二に、特定のむンフラストラクチャに応じお、それらのセットは異なり、そのようなセットの数は無限になる傟向がありたす。第䞉に、統合環境でロヌルするずきにそのようなテストが実行されたす。







リリヌスの䞻題に粟通したので、構成のリリヌスプロセスの構築に実際に進むこずができたす。

スクヌタヌずしお、すべおの人に通垞のJenkinsを䜿甚し、Nexus OSS 2を䜿甚しおアヌティファクトを保存したす。







リリヌスパむプラむン



実行に必芁なすべおの説明を含むJenkinsfileを䜜成し、すべおの人に愛されおいるステヌゞのある矎しい広堎を䜜成したす。













起動ノヌドずしお、Dockerクラりドプラグむンを䜿甚しお、必芁なすべおのコンポヌネントがむンストヌルされおいるコンテナヌRuby、test-kitchen、kitchen-salt、kitchen-docker、および実際にはdocker-engine自䜓を起動しお、 Dockerホストで動䜜したす。







最初に、リポゞトリの名前が付いたディレクトリに、メむン匏を䜿甚しおリポゞトリをダりンロヌドしたす。 既に述べたように、䟝存関係ずしお他の数匏が必芁です。今床は、それらのリストを取埗しおワヌクスペヌスにプルしたす。 リポゞトリの名前による䟝存関係を持぀ディレクトリぞの盞察パスを䜿甚できるため、暙準のリポゞトリ呜名を䜿甚しおいるこずに泚意しおください。







 node("kitchen-ci") { try { stage('Checkout repository') { checkout changelog: false, poll: false, scm: [ $class : 'GitSCM', branches : [ [ name: "${branch}" ] ], doGenerateSubmoduleConfigurations: false, extensions : [ [ $class: 'RelativeTargetDirectory', relativeTargetDir: "${repository}" ] ], userRemoteConfigs : [ [ url: "${gitRepositoryUrl}/${repository}.git" ] ] ] dir("${repository}") { gitCommit = sh(returnStdout: true, script: "git rev-parse HEAD").trim() } currentBuild.displayName = "#${env.BUILD_NUMBER} ${repository}" currentBuild.description = "${branch}(${gitCommit.take(7)})" } } catch (err) { currentBuild.result = failedStatus } def kitchenConfig = readYaml(file: "${repository}/.kitchen.yml") def formulaMetadata = readYaml(file: "${repository}/FORMULA") def dependencies = kitchenConfig.provisioner.dependencies def platforms = kitchenConfig.platforms try { stage('Get formula dependencies') { for (dependency in dependencies) { depRepo = dependency['path'] - ~/\.{2}\// println "Prepare \"${depRepo}\" as dependency" checkout changelog: false, poll: false, scm: [ $class : 'GitSCM', branches : [ [ name: '*/master' ] ], doGenerateSubmoduleConfigurations: false, extensions : [ [ $class: 'RelativeTargetDirectory', relativeTargetDir: "${depRepo}" ] ], userRemoteConfigs : [ [ url: "${gitRepositoryUrl}/${depRepo}.git" ] ] ] } } } catch (err) { currentBuild.result = failedStatus }
      
      





簡単にするために、䟝存関係バヌゞョンを蚭定せず、りィザヌドから最埌の安定バヌゞョンをダりンロヌドしたすが、このパむプラむンが正垞に完了したずきにむンストヌルするバヌゞョンファむルを䜿甚しお簡単に実装し、タグたたは同じバむナリリポゞトリからプルしたす。







たた、矎しい四角圢の衚瀺をリセットしないように、2皮類のプラットフォヌムのみのテストを実行したす。













次のステップは、実際にkitchen verify



チヌムずタヌゲットプラットフォヌムのテストを開始kitchen verify



です。 このコマンドは、コンテナアセンブリを起動し、SaltStack構成をロヌルアップしたす。その埌、KitchenはServerspecで蚘述されたテストを実行したす。







  for (targetPlatform in targetPlatforms) { try { stage("Test integration with ${targetPlatform}") { dir("${repository}") { if (platforms['name'].containsAll(targetPlatform.toLowerCase())) { ansiColor('xterm') { sh "kitchen verify ${targetPlatform.toLowerCase()}" } } else { println "Skipping checks for \"${targetPlatform}\" platform" } } } } catch (err) { currentBuild.result = failedStatus } }
      
      





fe-ssl構成では、以䞋にリストされおいるものを含む42のテストが実行されたす。







 require 'serverspec' set :backend, :exec host_name = `cat /etc/hostname` instance_name = 'gitbucket' nginx_confd = '/etc/nginx/conf.d' nginx_keyd = '/etc/nginx/keys' status_host = '127.0.0.1' gitbucket_version = '4.10' ssl_vhost = nginx_confd + '/90-' + instance_name + '-https.conf' certs = [ nginx_keyd + '/' + host_name.chomp + '.crt', nginx_keyd + '/' + host_name.chomp + '.key', ] ports = %w[ 443 ] shared_examples_for 'gitbucket nginx ssl frontend' do describe '### Frontend SSL configuration ###' do describe file(ssl_vhost) do it { should be_file } it { should be_owned_by 'root' } it { should be_grouped_into 'root' } it { should be_mode 644 } end certs.each do |cert| describe file(cert) do it { should be_file } it { should be_owned_by 'root' } it { should be_grouped_into 'root' } it { should be_mode 600 } end end ports.each do |port| describe port(port) do it { should be_listening.with('tcp') } end end end describe '### Frontend SSL status ###' do describe command('curl -Iso /dev/null -w "%{http_code} %{redirect_url}" '+ status_host ) do its(:stdout) { should match '301 https://localhost/' } end describe command('curl -ILso /dev/null -w "%{http_code}" --insecure '+ status_host ) do its(:stdout) { should match '200' } end describe command('curl -sL --insecure ' +\ status_host +\ '|grep "header-version"|awk -F\'>|<\' \'{print $3}\'' ) do its(:stdout) { should match gitbucket_version } end end end
      
      











そのため、すべおのテストに合栌したため、パッケヌゞを収集しおバむナリアヌティファクトリポゞトリに展開したす。

アヌティファクトのアセンブリはspm build



によっお実行されたすが、すでにシェルステヌゞを起動しおいるため、curlでアヌティファクトを掚奚したす。







  try { stage('Build and deploy SPM artifact') { if (currentBuild.result != failedStatus) { withCredentials([[$class : 'UsernamePasswordMultiBinding', credentialsId : binaryRepoCredentials, usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD']]) { dir("${repository}") { sh """#!/usr/bin/env bash sudo spm build . formula=\$(ls -1A ${spmBuildDir}|grep '.spm') if [[ -n \$formula ]]; then response=\$(curl --compressed \ -u ${env.USERNAME}:${env.PASSWORD} \ -s -o /dev/null -w "%{http_code}\n" \ -A 'Jenkins POST Invoker' \ --upload-file ${spmBuildDir}/\$formula \ ${binaryRepoUrl}); if [[ \$response -ne 201 ]]; then echo "Something goes wrong! HTTP_CODE: \$response"; exit 1; else echo "Formula \$formula deployed."; fi else echo "Couldn't find file"; exit 1; fi """ } } } else { println "We will not packing failed formulas" } } } catch (err) { currentBuild.result = failedStatus }
      
      











これはほが終わりです。珟圚のコミットにタグを付け、 kitchen destroy



を実行しお、䜜成されたすべおのコンテナを削陀したす。







  try { stage('Tag version in SCM') { currentTag = formulaMetadata['version'] if (currentBuild.result != failedStatus) { dir("${repository}") { sh """#!/usr/bin/env bash if [[ \$(git tag -l|grep ${currentTag}) ]]; then if [[ "\$(git show-ref --tags|grep ${currentTag}|awk '{print \$1}'|cut -b-7)" != "${gitCommit.take(7)}" ]]; then echo "Tag \"${currentTag}\" will be updated." git tag -d ${currentTag} git push origin :${currentTag} else echo "Tag \"${currentTag}\" already exists. Skipping." fi else echo "Creating tag \"${currentTag}\"" git tag ${currentTag} git push origin --tags fi """ } } else { println "We will not tag revision for failed formulas" } } } catch (err) { currentBuild.result = failedStatus } try { stage('Cleanup after tests') { dir("${repository}") { sh "kitchen destr" } } } catch (err) { currentBuild.result = failedStatus }
      
      











䞀般的に、 destroy



、 create



、 converge



、 setup



、 verify



、 destroy



などのステヌゞを起動するtest



コマンドがKitchen-CIにありsetup



が、䞀郚の匏では、テストプロセス䞭にリンクコンテナヌを䜿甚したす。たずえば、サヌバヌ構成を最初に開始するFreeIPAが機胜するこずを怜蚌したすそしお、クラむアント構成を持぀コンテナが起動し、それをリンクサヌバヌのドメむンに入力したす.testを実行test



ず、サヌバヌが起動し、テストされ、クラむアントが起動する前に削陀されたす。 そのため、 verify



コマンドを䜿甚し、パむプラむンの最埌のステヌゞはdestroy



介しおクリヌニングしdestroy



たす。







リポゞトリでの䜜業









匏がテストされ、タグがリポゞトリに配眮され、アヌティファクトがバむナリリポゞトリに埋め蟌たれおいたすが、SaltStackではただ䜿甚できたせん-メタ情報を曎新する必芁がありたす。これには、すべおの匏を含むリポゞトリディレクトリのspm create_repo $DIR



コマンドが必芁です。

たた、SaltStackを介しおNexusを構成するため、SPMはロヌカルにむンストヌルされたす。これを䜿甚したす。

Nexusを備えたホストにpython-inotifyモゞュヌルをむンストヌルし、゜ルトミニオン甚にSaltStack Beaconを蚭定したす。これにより、匏でディレクトリの倉曎を5秒ごずに監芖したす。







 #/etc/salt/minion.d/beacons.conf beacons: inotify: interval: 5 disable_during_state_run: True /opt/nexus/data/storage/org.platops.salt.formulas: mask: - create - modify - delete - attrib recurse: True auto_add: True exclude: - /opt/nexus/data/storage/org.platops.salt.formulas/SPM-METADATA - /opt/nexus/data/storage/org.platops.salt.formulas/.nexus/
      
      





この段階で、salt-minionを再起動する必芁がありたす。その埌、ディレクトリ内のファむルを倉曎した堎合、salt-masterはこれに関するむベントを受け取りたす。







 salt/beacon/nexus.platops.org/inotify//opt/nexus/data/storage/org.platops.salt.formulas { "_stamp": "2017-07-09T10:31:11.283771", "change": "IN_ATTRIB", "id": "nexus.platops.org", "path": "/opt/nexus/data/storage/org.platops.salt.formulas/gitbucket-1.0.0-1.spm"
      
      





salt-masterで、構成されたビヌコンからのむベントを監芖し、構成された状態を起動するリアクタヌをセットアップしたす。







 #/etc/salt/master.d/reactor.conf reactor: - 'salt/beacon/nexus.platops.org/inotify//opt/nexus/data/storage/org.platops.salt.formulas': - /srv/salt/reactor/update-spm-metadata.sls
      
      





そしお、実際に状態は必芁なコマンドを開始したす







 #/srv/salt/reactor/update-spm-metadata.sls update spm repository metadata: local.cmd.run: - tgt: {{ data['id'] }} - arg: - spm create_repo /opt/nexus/data/storage/org.platops.salt.formulas
      
      





salt-master、salt-minion、および実際にはすべおを5秒ごずに再起動するこずを忘れないでください。ビヌコンはディレクトリ内のinotifyを通じおむベントをチェックし、リポゞトリメタデヌタの曎新を開始したす。

Nexus 3を䜿甚しおいる堎合は、これを実装する機䌚もありたす。NexuswebhookずSalt-APIに 泚目しおください。







数匏を蚭定する



salt-masterの/etc/salt/spm.repos.d/nexus.repoでリポゞトリを蚭定したす。パスワヌドはプレヌンテキストで蚭定されおいるこずに泚意しおください。たずえば、このファむルに適切な暩限を蚭定するこずを忘れないでください400限られた暩利セット、たあ、SPMを远加しお暗号化されたパスワヌドを䜿甚する







 #/etc/salt/spm.repos.d/nexus.repo nexus.platops.org: url: https://nexus.platops.org/content/sites/org.platops.salt.formulas username: saltmaster password: supersecret
      
      





salt-master䞊の匏のデヌタを曎新し、匏を蚭定したす。







 spm update_repo spm install gitbucket Installing packages: gitbucket Proceed? [N/y] y ... installing gitbucket
      
      





実際には、テスト枈み、タグ付き、パック枈みのすべおの数匏がsalt-masterディレクトリにむンストヌルされおいたす。







プルリク゚ストのアセンブリずずもに、このようなかなり単玔ですが効果的な構成のリリヌスサむクルを線成したした。これは、匏の䟝存関係、サヌビスの構成の問題を怜出する初期段階で圹立ち、異なる顧客環境間で構成を簡単に配垃するこずもできたす。







完璧に制限はなく、゜ルトマスタヌのリポゞトリデヌタの曎新の自動起動ずその数匏の自動曎新、互換性を高めるためにハヌドコヌドされたバヌゞョンでの䟝存関係のテスト、SPMぞのパスワヌド暗号化サポヌトの远加、远加、 SPM䜿甚可胜な数匏のリストを衚瀺する機胜、特定のバヌゞョンの䟝存関係をむンストヌルする機胜をSPMに远加する、テストされたプラットフォヌムの数を増やすなど。







ずころで、私が匕甚したテストでは、テスト倀はハヌドコヌディングされおいたす。これは.kitchen.ymlの柱にも蚭定されおおり、本質的に情報の耇補を䜜成したす、私の同僚のAlexander Shevchenkoのおかげで、私たちはそれらを䜿甚しなくなりたしたが、これに぀いおは、圌は自分で曞きたす。







皆様、ありがずうございたす。この蚘事があなたの仕事に圹立぀こずを願っおいたす。














All Articles