りラルIT局の1぀の小芏暡プロゞェクトの䟋に関するCI / CDパむプラむン

アクタヌチヌム開発者-2人、管理者-1人。



この蚘事では、Ansible、Docker Swarm、Jenkins、Portainerなどのテクノロゞヌを䜿甚しお、矎しいWebむンタヌフェヌスを䜿甚しお制埡できるCI / CDパむプラむンを実装する方法に぀いお説明しおいたす。







゚ントリヌ



開発者は通垞䜕を望んでいたすか 圌はお金を考えずに、そしお自分の創造性の結果をできるだけ早く芋たいず考えおいたす。



䞀方、より倚くのお金を必芁ずするビゞネスがあるため、補品を垂堎に出すたでの時間を短瞮するこずを垞に考えおいたす。 蚀い換えれば、ビゞネスは、MVP別名、Minimum Viable Productの買収を新補品たたは既存補品の曎新時にスピヌドアップするこずを倢芋おいたす。



さお、管理者は䜕を望んでいたすか そしお、管理者は単玔な人です。圌はサヌビスが萜ちず、 Kwaku Tanksのプレむに干枉しないこずを望んでいたす。

人生の真実が瀺すように、管理者の欲望を実珟するために、他のヒヌロヌの倢も圌の力によっお実珟されなければならないため、ITパヌティヌの代衚者はこれに倚くの努力をしたした。 倚くの堎合、DevOps方法論に準拠し、CI / CD継続的むンテグレヌションず配信の原則を実装しお、目的を達成するこずができたした。



これは、Urals IT Directorateの小さなプロゞェクトで発生したした。このプロゞェクトでは、開発者がバヌゞョン管理システムに゜ヌスの倉曎を公開し、テスト環境でアプリケヌションの新しいバヌゞョンを自動的に起動するたでの完党なパむプラむンを短時間で実装するこずができたした。



パヌト0。タスクの説明



システム構成



議論の埌、チヌムは次の2局アヌキテクチャを遞択したした。





次に、これらのコンポヌネントにNGINXサヌバヌが远加されたした。これはNodeJSアプリケヌションのフロント゚ンドです。 その圹割は、アプリケヌション自䜓ずシステムの他のむンフラストラクチャコンポヌネント間で芁求を分散するこずでした。これに぀いおは、以䞋で説明したす。



チヌムは䜕を求めおいたしたか



新しいプロゞェクトに青信号が䞎えられるずすぐに、最初の技術的タスク、すなわち、新しいプロゞェクトを立ち䞊げるための「機噚」の準備が珟れたした。 すべおの参加者にずっお、新しいバヌゞョンをサヌバヌにロヌルアりトする最倧の効率がなければ、プロゞェクトの開発は非垞に難しいこずは明らかだったので、すぐに完党なCI / CDのパスに埓うこずになりたした 私は次のパむプラむンを達成したいず思いたした。





  1. ゜ヌスのコンパむルず初期テスト。
  2. Dockerむメヌゞの新しいバヌゞョンを組み立おたす2018幎にベアメタルたたは仮想マシンに䜕かを展開するのは䞋品です、圌らは理解したせん。
  3. Artifactoryバむナリアヌティファクトのストレヌゞおよび管理システム、掚奚で画像を公開したす。
  4. 曎新があたり成功しなかった堎合に、サヌバヌ䞊のアプリケヌションの新しいバヌゞョンたたはアプリケヌションの「スタック」党䜓を前のバヌゞョンに「ロヌルバック」しお再起動する。


フレヌムワヌク



このテヌマの人々は、おそらく「クベルネテスやメ゜ス/マラ゜ンのような「生産準備の敎った」゜リュヌションではなく、束葉杖を䜿甚しおいるのはなぜか」ず質問しおいるでしょう。 同様の質問は非垞に合理的であるため、説明した゜リュヌションは次のようなさたざたな理由で䜿甚されたずすぐに蚀っおください。





ただし、゜リュヌションが束葉杖の豊富なファミリに属しおいるこずを忘れないでください。近い将来、より暙準的なOpenShift + Bambooスタックに移行するこずを望んでいたす。



さらに、この蚘事はWeb指向のアプリケヌションのみに関係し、デヌタがおそらくどこかにあるのにデヌタがどこかにあり、保存するこずを考えおいない堎合のステヌトレスアヌキテクチャの理想的なケヌスに぀いおも説明したす。



パヌト1.ホストシステムでの゜フトりェアのむンストヌルず基本構成



チェヌン党䜓の自動化ず高い再珟性を最倧化するために、ホストシステムVMWare / qemu KVM /クラりド/その他に基づく仮想マシンは、Ansible構成管理システムを䜿甚しお構成するこずにしたした。



簡単な再珟性ず再珟性に加えお、このようなシステムAnsibleの他に、PuppetずChefシステムもありたすの䜿甚は、various等の圢匏でのさたざたなシェルたたはpythonスクリプトの䜿甚よりも倧きな利点があるこずを付け加える䟡倀がありたす。 繰り返し起動しおもシステムの最終状態が倉わらないプロパティ。



この利点は、構成管理システムを䜿甚する堎合、蚘述されるのは望たしい状態を達成するプロセスではなく、宣蚀的な圢での望たしい状態自䜓であるずいう事実に由来したす。



1.1 ssh HostKeyChecking



デフォルトでは、Ansibleはセキュリティを尊重し、リモヌト蚭定可胜ホストのsshフィンガヌプリントを怜蚌したす。 なぜなら このモヌドでは、パスワヌドで認蚌する機胜が無効になりたす。その埌、サヌバヌの初期セットアップでHostKeyCheckingを無効にするか、最初にロヌカルキャッシュに指王を远加する必芁がありたす。 埌者は2぀の方法で実珟できたす。



たたは



特別な環境倉数を定矩したす。



$ export ANSIBLE_HOST_KEY_CHECKING=False
      
      





たたは別の方法で



host_key_checkingパラメヌタヌをロヌカルのansible.cfg構成ファむルに远加したす。



 [defaults] host_key_checking = False
      
      





最初の方法では、このような環境倉数が存圚する間のみチェックが無効になり、2番目の方法ではこのホストに察しお完党に無効になりたす。



1.2むンベントリ



むンベントリは、蚭定を制埡する必芁があるホストずそのグルヌプを蚘述するAnsibleシステムの゚ンティティです。



むンベントリは、iniたたはyaml圢匏で蚘述できたす。 このプロゞェクトでは、最埌のプロゞェクトが遞択されたした。



hosts.ymlファむルの䟋



 #_  all   all: hosts: #    ,     Ansible some-cool-vm-host vars: #  ,    ansible_user: 'root' #    ,       :-( ansible_password: '12345678' #     corp_ca_crt: "-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----"
      
      





yaml圢匏に初めお盎面したずき、この圢匏のすべおのむンデントはスペヌスで埋めなければならないこずに泚意したいず思いたす。



1.3プレむブック



PlaybookはAnsibleの別の゚ンティティであり、Inventoryからホストずグルヌプの望たしい最終状態を宣蚀的に盎接蚘述したす。 Ansibleのほずんどすべおのものず同様に、プレむブックはyaml圢匏のファむルで蚘述されたす。



プレむブックファむルを実行するには、次の圢匏のコマンドを実行する必芁がありたす。



 ansible-playbook -i ./hosts.yml tasks.yml
      
      





このプレむブックでは、必芁なナヌザヌの䜜成ずDockerのむンストヌルを含む基本システムの完党なセットアップに぀いお説明したした。



 #_      ,       () - hosts: all tasks: #   - name:      shell: rm /etc/zypp/repos.d/* || exit 0 - name:   SLES-   REPOs... zypper_repository: repo="{{ item.repo }}" name="{{ item.name }}" disable_gpg_check="{{ item.disable_gpg_check|default('no') }}" with_items: - { repo: "http://...", name: "SLE-DISTRO-X" } - name:       zypper: name: '*' state: latest - name:    CA   copy: #     Inventory content: '{{ corp_ca_crt }}' dest: /etc/pki/trust/anchors/orpCA.crt owner: root group: root mode: 0644 - name: ...     shell: update-ca-certificates - name:     group: name="{{ item.name }}" gid={{ item.gid }} state="present" with_items: - { name: "docker", gid: 1000 } - user: name: "{{ item.name }}" uid: "{{ item.uid }}" group: "{{ item.gid }}" state: "present" with_items: - { name: "dockeradm", uid: 1000, gid: "docker" } - name:    user: name: "{{ item }}" password: "$6$..." generate_ssh_key: yes with_items: - root - dockeradm - name:   ssh-          authorized_key: user: "{{ item }}" key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}" state: "present" with_items: - root - dockeradm - name:   VG   lvg: vg: 'vgAPP' pvs: '/dev/sdb' - name: ...  LV lvol: vg: "{{ item.vg }}" lv: "{{ item.lv }}" size: "{{ item.size }}" with_items: - { vg: 'vgAPP', lv: "lvData", size: "10G" } - { vg: 'vgAPP', lv: "lvDockerData", size: "5G" } - name:     LV- filesystem: dev="/dev/{{ item }}" fstype="btrfs" with_items: - 'vgAPP/lvData' - 'vgAPP/lvDockerData' - name:      /etc/fstab    mount: path="{{ item.dst }}" src="/dev/{{ item.src }}" state="mounted" fstype="btrfs" opts="noatime" with_items: - { src: "vgAPP/lvData", dst: "/APP" } - { src: "vgAPP/lvDockerData", dst: "/var/lib/docker" } - name:     file: path: "{{ item.path }}" state: "directory" #     mode: "0{{ item.perms|default('755') }}" owner: "{{ item.user|default('dockeradm') }}" group: "{{ item.group|default('docker') }}" with_items: - { path: '/etc/docker', user: 'root', group: 'root' } - { path: '/APP' } - { path: '/APP/configs' } - { path: '/APP/configs/filebeat' } - { path: '/APP/logs' } - { path: '/APP/logs/nginx' } - { path: '/APP/jenkins' } - { path: '/APP/jenkins/master' } - { path: '/APP/jenkins/node' } - { path: '/APP/portainer_data' } - name:      zypper: name: '{{ item }}' with_items: - docker - mc # Java    Jenkins- - java-1_8_0-openjdk-headless #        - name:  -  " " template: src: daemon.json dest: /etc/docker/daemon.json owner: root group: root mode: 0644 - name:    ... systemd: name: "{{ item }}" state: 'restarted' enabled: 'yes' with_items: - docker - sshd - name:     docker-compose     get_url: url: "https://github.com/docker/compose/releases/download/1.18.0/docker-compose-Linux-x86_64" dest: "/tmp/docker-compose" delegate_to: 127.0.0.1 - copy: src: "/tmp/docker-compose" dest: "/usr/local/bin/docker-compose" mode: "u=rwx,g=rx,o=rx" - name:  - NGINX,     template: src: nginx.conf dest: /APP/configs/nginx.conf owner: dockeradm group: docker mode: '0644' - name:   docker-compose - ,     template: src: docker-compose.yml dest: /APP/docker-compose.yml owner: dockeradm group: docker mode: '0644' - name:  docker-compose -   Jenkins, Portainer  NGINX   shell: docker-compose -f /APP/docker-compose.yml up -d --force-recreate - name:    Jenkins- wait_for: path: '/APP/jenkins/master/secrets/initialAdminPassword' - name:     Jenkins fetch: src: '/APP/jenkins/master/secrets/initialAdminPassword' dest: initialJenkinsAdminPassword.txt flat: yes
      
      





パヌト2.プロゞェクトサヌビス



2.1 CIサヌバヌずプロセス



有名なJenkins CIサヌバヌは、プロゞェクトの「継続的な統合ず展開」のプロセスを担圓したす。



䞊蚘のAnsibleプレむブックコヌドは、実行の最埌に、新しくむンストヌルされたJenkinsがサヌバヌDockerコンテナヌ内で既に実行され、その䞀時パスワヌドがinitialJenkinsAdminPassword.txtファむルのLOCALマシンに保存されるように蚭蚈されおいたす。



チヌム党䜓がコヌドずしおのむンフラストラクチャIaCの理想的なケヌスにできるだけ近づけるこずを望んでいたため、プロゞェクトのタスクは、Groovyスクリプト蚀語でタスクが蚘述され、そのコヌドがプロゞェクト゜ヌスの隣に栌玍されおいる堎合、 宣蚀およびスクリプト化された Jenkinsパむプラむンの圢匏で実装されたしたバヌゞョン管理システムgit。



Spring Bootでアプリケヌションのバック゚ンド郚分を組み立おるためのパむプラむンの䟋を以䞋に瀺したす。



 pipeline { agent { # ,      # Docker-    : docker { image 'java:8-jdk' } } stages { stage('   ') { steps { checkout scm } } stage('') { steps { sh 'chmod +x ./gradlew' sh './gradlew build -x test' } } stage('') { steps { script { sh './gradlew test' } } } } } #_    Docker-      Artifactory: node { stage(' ') { docker.withRegistry("https://repo.artifactory.bank", "LoginToArtifactory") { def dkrImg = docker.build("repo.artifactory.bank/dev-backend:${env.BUILD_ID}") dkrImg.push() dkrImg.push('latest') } } stage('   Artifactory') { docker.withRegistry("https://repo.artifactory.bank", "LoginToArtifactory") { sh "docker service update --image repo.artifactory.bank/dev-backend:${env.BUILD_ID} SMB_dev-backend" } } }
      
      





画像を組み立おるずきに、各バヌゞョンが独自のタグラベルを取埗するため、アプリケヌションの自動再起動プロセスが倧幅に容易になるこずに泚意しおください。



2.2ポヌテむナヌ



プロゞェクトのすべおのチヌムメンバヌずDockerの盞互䜜甚を促進するために、単玔なWebむンタヌフェヌスであるPortainerを䜿甚したした。 このアプリケヌションは、Docker自䜓ず同様にGoで蚘述されおいるため、非垞に簡単に展開できる高いパフォヌマンスが特城です。



たずえば、最も単玔な堎合、次のコマンドはホストシステムのポヌト9000でPorteinerを起動したす。



 docker run -d \ -p 9000:9000 \ -v /var/run/docker.sock:/var/run/docker.sock \ portainer/portainer
      
      





ただし、珟圚のプロゞェクトでは、1぀のホスト Docker Composeに察しお「オヌケストレヌション」ツヌルの機胜を䜿甚するこずが決定されたした。



2.3 Dockerコンテナヌずサヌビス



このプロゞェクトで必芁なすべおのアプリケヌションずサヌビスは、単玔なdocker-compose.ymlファむルを介しお起動されたす。



「むンフラストラクチャ」サヌビスの基本セットは、次の説明を通じお開始されたす。



 version: '3.4' services: #     NGINX nginx: image: "nginx:1" container_name: fe-nginx restart: always volumes: - /APP/configs/nginx.conf:/etc/nginx/nginx.conf - /APP/logs/nginx:/var/log/nginx - /usr/share/zoneinfo/Europe/Moscow:/etc/localtime:ro networks: - int ports: - "80:80/tcp" - "8080:80/tcp" # Jenkins CI - ,    CI/CD- ci: image: "jenkins/jenkins:lts" container_name: ci-jenkins restart: always volumes: - /usr/share/zoneinfo/Europe/Moscow:/etc/localtime:ro - /APP/jenkins/master:/var/jenkins_home environment: JENKINS_OPTS: '--prefix=/jenkinsci' JAVA_OPTS: '-Xmx512m' networks: int: aliases: - srv-ci # -  Docker- portainer: image: "portainer/portainer:latest" volumes: - type: bind source: /var/run/docker.sock target: /var/run/docker.sock - type: bind source: /APP/portainer_data target: /data networks: int: aliases: - srv-portainer command: -H 'unix:///var/run/docker.sock' networks: int: external: true
      
      





2.4クラスタヌなしのDocker Swarmクラスタヌ



䞊蚘のdocker-compose.ymlファむルを芋るずわかるように、たず、アプリケヌションのバック゚ンド郚分ずフロント゚ンド郚分ぞの参照がなく、intずいう名前の「倖郚」倖郚trueネットワヌクぞのリンクもありたす。 倖郚リ゜ヌスずは、単䞀のファむルで宣蚀されおいないリ゜ヌスネットワヌク、ボリュヌム、およびその他の既存の゚ンティティです。



実際のずころ、プロゞェクトでは、Artifactory Dockerリポゞトリ内のむメヌゞのバヌゞョンを曎新するずきに「サヌビス」を再起動できる必芁があり、同様の機胜がDocker SwarmサヌビスDockerコンテナ甚のDockerマルチマスタヌ組み蟌みオヌケストレヌションシステムに存圚し、箱から出しお。」 この機胜は、実行䞭のサヌビスの必芁なむメヌゞを倉曎する機胜を通じお実装され、リポゞトリにむメヌゞの新しいバヌゞョンがある堎合、再起動は自動的に行われたす。 バヌゞョンが倉曎されおいない堎合、サヌビスコンテナは匕き続き正垞に実行されたす。



ネットワヌクに぀いおは、Docker Swarmサヌビスの圢匏でアプリケヌションを起動するずきにyamlの説明を以䞋に瀺したす、䞊蚘で発衚したコンポヌネントずNGINXサヌバヌのネットワヌク接続を維持する必芁がありたした。 これは、䞊蚘の基本サヌビスずアプリケヌションコンポヌネント自䜓の䞡方を含むサヌバヌクラスタヌ䞊にオヌバヌレむネットワヌクを䜜成するこずで実珟したした。



 docker network create -d overlay --subnet 10.1.2.254/24 --attachable int
      
      





-それがなければ、基本サヌビスはクラスタヌネットワヌクにアクセスできないため、接続可胜が必芁です



2぀のサヌビスを備えたアプリケヌションコンポヌネントの説明



 version: '3.2' services: pre-live-backend: image:repo.artifactory.bank/dev-backend:latest deploy: mode: replicated replicas: 1 networks: - int pre-live-front: image: repo.artifactory.bank/dev-front:latest deploy: mode: replicated replicas: 1 networks: - int networks: int: external: true
      
      





おわりに



冒頭で述べたように、プロゞェクトの開始時に、チヌムはDevOpsアプロヌチのすべおの利点を取埗したいず考えおいたした。特に、Gitリポゞトリから実行䞭のアプリケヌションずしお「バトル」サヌバヌにコヌドを継続的に配信するプロセスを敎理したいず考えおいたした。 同時に、珟圚の段階では、確立された慣行を完党に攟棄し、倧芏暡なオヌケストレヌタヌの䞖界での生掻の䞭で自分自身を再構築したくありたせんでした。 説明されたシステムアヌキテクチャは、2週間未満でチヌムメンバヌが取り組んでいた他のプロゞェクトず䞊行しお考え出されお実装され、最終的に私たちが望むものを達成するこずができたした。 この資料は、DevOpsアプロヌチを実装する他のチヌムにずっお興味深く有甚であるず考えおいたす。



All Articles