everything as a code

154
Everything as a Code Непривычно о привычном

Upload: aleksandr-tarasov

Post on 11-Apr-2017

196 views

Category:

Technology


1 download

TRANSCRIPT

Page 1: Everything as a code

Everything as a CodeНепривычно о привычном

Page 2: Everything as a code

@aatarasoff

@aatarasoff

@aatarasoff

Page 3: Everything as a code

No warranty guarantee

Page 4: Everything as a code

Matrix has you

4

Page 5: Everything as a code

5

Page 6: Everything as a code

6

Page 7: Everything as a code

Выйти за пределы...

7

Page 8: Everything as a code

...поняв, что всё есть код

8

Page 9: Everything as a code

Как вы представляете себе код?

9

Page 10: Everything as a code

@Configuration@EnableConfigurationProperties(OneServerProperties.class)public class OneServerConfiguration implements ApplicationContextAware { ApplicationContext applicationContext;

@Autowired OneServerProperties properties;

@Bean public HttpServer httpServer() throws IOException { HttpServer httpServer = new RelativePathHttpServer();

for (String beanName : context.getBeans(HttpController.class)) { httpServer.addRequestHandlers(context.getBean(beanName)); }

return httpServer; }}

10

Наверное как-то так

Page 11: Everything as a code

Что такое код?

● Коллекция инструкций

● Человекочитаемый формат

○ plain text

● Может быть понят и “проигран”

○ после компиляции

○ интерпретатором

11

Page 12: Everything as a code

Да я тоже пишу код!

12

Page 13: Everything as a code

Вооружи себя

13

Page 14: Everything as a code

Настройка рабочего окружения

14

Page 15: Everything as a code

Install apps Code Checkout Configure workspace First Blood

15

Page 16: Everything as a code

Install apps Code Checkout Configure workspace First Blood

brew install

16

Page 17: Everything as a code

Install apps Code Checkout Configure workspace First Blood

brew installpip install

17

Page 18: Everything as a code

Install apps Code Checkout Configure workspace First Blood

git

18

Page 19: Everything as a code

Install apps Code Checkout Configure workspace First Blood

customize*.properties

19

Page 20: Everything as a code

Install apps Code Checkout Configure workspace First Blood

customize*.propertiestemplate

.gradle

20

Page 21: Everything as a code

Install apps Code Checkout Configure workspace First Blood

customize*.propertiesinstall

certificates

21

Page 22: Everything as a code

Install apps Code Checkout Configure workspace First Blood

first build

22

Page 23: Everything as a code

Install apps Code Checkout Configure workspace First Blood

mass buildfirst deploy

23

Page 24: Everything as a code

ansible-playbook -i local-inv setup.yml --tags configure

24

Интерпретатор

Page 25: Everything as a code

ansible-playbook -i local-inv setup.yml --tags configure

25

Конфигурация

Page 26: Everything as a code

ansible-playbook -i local-inv setup.yml --tags configure

26

Алгоритм

Page 27: Everything as a code

#checkout repositories from git- include: checkout.yml

#configure your local environment- include: configure.yml

#add useful mappings to your hosts file- include: hosts.yml

#add gradle support- include: gradle.yml

#clean and build all projects- include: build.yml

#delpoy all services to dev- include: build.yml

27

Алгоритм

Page 28: Everything as a code

ansible-playbook -i local-inv setup.yml --tags configure

28

Входные параметры

Page 29: Everything as a code

- name: checkout services git: repo: "{{ git.root }}/{{ item.name }}.git" dest: "{{ work_dir }}/{{ item.name }}" update: yes with_items: - "{{ services }}" tags: - services

29

Массовый checkout/pull

Page 30: Everything as a code

- name: checkout services git: repo: "{{ git.root }}/{{ item.name }}.git" dest: "{{ work_dir }}/{{ item.name }}" update: yes with_items: - "{{ services }}" tags: - services

Переменные

30

Page 31: Everything as a code

- name: checkout services git: // with_items: - "{{ services }}"

services: - { name: one-instant-messenger , sourceDir: src } - { name: one-discussions, sourceDir: src } - { name: one-attachment, sourceDir: src, testDir: test, local: true }

Циклы

31

Page 32: Everything as a code

services: - { name: one-instant-messenger, sourceDir: src } - { name: one-discussions, sourceDir: src } - { name: one-attachment, sourceDir: src, testDir: test }

Коллекции и структуры данных

32

Page 33: Everything as a code

- name: create gradle build file template: src: build.gradle.j2 dest: "{{ work_dir }}/build.gradle" mode: 0644

- name: create gradle settings file template: src: settings.gradle.j2 dest: "{{ work_dir }}/settings.gradle" mode: 0644

Шаблоны

33

Page 34: Everything as a code

{% if services is not none %}{% for service in services %} if (project.name == '{{ service.name }}') {{% if 'sourceDir' in service %} main.java.srcDir '{{ service.sourceDir }}'{% endif %}{% if 'testDir' in service %} test.java.srcDir '{{ service.testDir }}'{% endif %} }

Условные операторы

34

Page 35: Everything as a code

{% if services is not none %}{% for service in services %} if (project.name == '{{ service.name }}') {{% if 'sourceDir' in service %} main.java.srcDir '{{ service.sourceDir }}'{% endif %}{% if 'testDir' in service %} test.java.srcDir '{{ service.testDir }}'{% endif %} }

Опять циклы

35

Page 36: Everything as a code

- stat: path={{ username }}.key register: certkey

- name: generate private key shell: openssl genrsa -out {{ username }}.key -aes256 4096 when: not certkey.stat.exists

Идемпотентность

36

Page 37: Everything as a code

Install apps Code Checkout Configure workspace Multiplie Use

37

Петля обратной связи

git

Page 38: Everything as a code

Что получили

● Автоконфигурация рабочего

пространства

○ повторяемая

○ немутабельная

● Можно дать скрипт новичку

● Можно и нужно пользоваться этим

каждый день

38

Page 39: Everything as a code

Код есть код

39

Page 40: Everything as a code

Искусство сборки

40

Page 41: Everything as a code

Compile code Unit tests Package Publishing

41

Page 42: Everything as a code

Compile code Unit tests Package

compiler

Publishing

42

Page 43: Everything as a code

Compile code Unit tests Package

javacresourceprocessing

Publishing

43

Page 44: Everything as a code

Compile code Unit tests Package

javacresources copyingdependency resolving

Publishing

44

Page 45: Everything as a code

Compile code Unit tests Package

junit

Publishing

45

Page 46: Everything as a code

Compile code Unit tests Package

jar

Publishing

46

Page 47: Everything as a code

Compile code Unit tests Package

jarnpm, deb, ...

Publishing

47

Page 48: Everything as a code

Compile code Unit tests Package

jarnpm, so, ...docker image

Publishing

48

Page 49: Everything as a code

Compile code Unit tests Package

ivy

Publishing

49

Page 50: Everything as a code

Compile code Unit tests Package

maven, ivymaven

Publishing

50

Page 51: Everything as a code

Compile code Unit tests Package Publishing

maven, ivylocal or dev deploydocker registry

51

Page 52: Everything as a code

Системы сборки

● Ant + Ivy

● Maven

● Gradle

● Docker

● npm

● ...

52

Page 53: Everything as a code

FROM golang:1.7-alpineMAINTAINER [email protected]

VOLUME /dataWORKDIR /data

RUN apk update && \ apk upgrade && \ apk add git bash

RUN go get github.com/aatarasoff/apistress && \ go install github.com/aatarasoff/apistress

CMD [ "apistress" ]

Dockerfile. Наследование

53

Page 54: Everything as a code

FROM golang:1.7-alpineMAINTAINER [email protected]

VOLUME /dataWORKDIR /data

RUN apk update && \ apk upgrade && \ apk add git bash

RUN go get github.com/aatarasoff/apistress && \ go install github.com/aatarasoff/apistress

CMD [ "apistress" ]

Dockerfile. Инструкции

54

Page 55: Everything as a code

FROM golang:1.7-alpineMAINTAINER [email protected]

ARG maindir=/data

VOLUME $maindirWORKDIR $maindir

RUN apk update && apk upgrade && apk add git bash

RUN go get github.com/aatarasoff/apistress && \ go install github.com/aatarasoff/apistress

CMD [ "apistress" ]

Dockerfile. Переменные

55

Page 56: Everything as a code

docker build … && docker push …

56

Page 57: Everything as a code

publishing { publications { mavenJava(MavenPublication) { artifactId 'spring-one-nio-autoconfigure'

from components.java

artifact sourceJar { classifier "sources" } } }}

Gradle. DSL

57

Page 58: Everything as a code

compile(ivyDependencies(projectDir, 'runtime'))

def ivyDependencies(ivyPath, conf) { def dep = [] def ivyModule = new XmlParser().parse(file("${ivyPath}/ivy.xml"))

ivyModule.dependencies.dependency.each dep.add([group: (null == it.@org ? 'ru.odnoklassniki' : it.@org), name: it.@name, version: it.@rev, configuration: (it.@conf =~ /->(\w+)/)[0][1]]) }

return dep}

Gradle. Ну просто код

58

Page 59: Everything as a code

<macrodef name="docker-build-image" description="Build docker image"> <attribute name=" buildcommand"

default="build -t @{repo}/@{image}:@{tag} ."/>

<sequential> <exec executable="docker"> <arg line=" @{buildcommand}"/> </exec> </sequential></macrodef>

И даже в Ant-е есть жизнь

59

Page 60: Everything as a code

./gradlew build test ant-docker-build-image publish

60

Page 61: Everything as a code

Фреймворки для автоматизации

● Ant + Ivy

● Maven

● Gradle

● Docker

● npm

● ...

61

Page 62: Everything as a code

Что получили

● Сборка это код

○ XML

○ DSL

○ Groovy

○ etc

● Системы сборки не только для

сборки

62

Page 63: Everything as a code

Ликвидация багов

63

Page 64: Everything as a code

Unit tests API tests Stress tests UI tests

64

Page 65: Everything as a code

Unit tests API tests Stress tests UI tests

TDD

65

Page 66: Everything as a code

Unit tests API tests Stress tests UI tests

BDD Specs

66

Page 67: Everything as a code

def "Return error code 400, if User-ID header is not presented"() { given: def request = post("/rent")

when: def result = this.mvc.perform(request)

then: result.andExpect(status().isBadRequest()) .andDo(document("rent-user-id-is-absent"))}

Дружелюбный BDD

67

Page 68: Everything as a code

def "Return error code 400, if User-ID header is not presented"() { given: def request = post("/rent")

when: def result = this.mvc.perform(request)

then: result.andExpect( status().isBadRequest()) .andDo(document("rent-user-id-is-absent"))}

Простые проверки

68

Page 69: Everything as a code

Unit tests API tests Stress tests UI tests

JMeter, wrk, vegeta

69

Page 70: Everything as a code

Unit tests API tests Stress tests UI tests

JMeterproduction

70

Page 71: Everything as a code

{ "baseUrl": "http://host:9000/rent-service", "tests": [ { "rps": 10, "duration": 5, "target": { "method": "GET", "path": "/rent", "headers": [ ... ] }, "sla": { "latency": 1000, "successRate": 99.999 } }, ... ]}

config.json

71

Page 72: Everything as a code

{ "baseUrl": "http://host:9000/rent-service", "tests": [ { "rps": 10, "duration": 5, "target": { "method": "GET", "path": "/rent", "headers": [ ... ] }, "sla": { "latency": 1000, "successRate": 99.999 } }, ... ]}

config.json

72

Page 73: Everything as a code

{ "baseUrl": "http://host:9000/rent-service", "tests": [ { "rps": 10, "duration": 5, "target": { "method": "GET", "path": "/rent", "headers": [ ... ] }, "sla": { "latency": 1000, "successRate": 99.999 } }, ... ]}

config.json

73

Page 74: Everything as a code

cat config.json | docker run -i apistress -config=stdin

74

Где-то мы такое видели

Page 75: Everything as a code

Requests [total, rate] 50, 10.20Duration [total, attack, wait] 5.022872793s, 4.899943287s, 122.929506msLatencies [mean, 50, 95, 99, max] 143.772484ms, ..., 290.101831msBytes In [total, mean] 4842, 96.84Bytes Out [total, mean] 950, 19.00Success [ratio] 100.00%Status Codes [code:count] 200:50Error Set:

Test#1

75

Page 76: Everything as a code

> cat config.json | docker run -i apistress -config=stdin> echo $?0

76

Код возврата

Page 77: Everything as a code

Requests [total, rate] 200, 10.05Duration [total, attack, wait] 23.04784s, 19.899754743s, 3.148093811sLatencies [mean, 50, 95, 99, max] 3.023677499s, ..., 11.832287083sBytes In [total, mean] 6874, 34.37Bytes Out [total, mean] 1349, 6.75Success [ratio] 35.50%Status Codes [code:count] 0:129 200:71Error Set:Get http://host:9000/rent-service/rent: EOFGet http://host:9000/rent-service/rent: http: server closed idle connection...

Test#2

77

Page 78: Everything as a code

> cat config.json | docker run -i apistress -config=stdin> echo $?1

78

Код возврата

Page 79: Everything as a code

Unit tests API tests Stress tests UI tests

Selenium, Selenide

79

Page 80: Everything as a code

Что получили

● Все тестовые сценарии в коде

● Можно встроить в процесс сборки

или доставки ПО

● Если хотите, то можно

генерировать отчёты для разбора

полётов

80

Page 81: Everything as a code

Кододокументация

81

Page 82: Everything as a code

Analyst, PM Developer Tester Docs

Word, PDF...

82

Page 83: Everything as a code

Analyst, PM Developer Tester Docs

Word, PDF... Code + Tests

83

Page 84: Everything as a code

Analyst, PM Developer Tester Docs

Word, PDF... Code + Tests Test cases

84

Page 85: Everything as a code

Analyst, PM Developer Tester Docs :(

Word, PDF... Code + Tests Test cases

85

Page 86: Everything as a code

Analyst, PM Developer Tester Docs :)

Markdown/Asciidoctor

Docs :)

86

Page 87: Everything as a code

= Hippo Rent ServiceThis is documentation for Open API of our hippo renting service

== Methods

=== Rent

==== Request specification===== Headers//тут опишем http-заголовки===== Example//а здесь будут примеры вызова

==== Response specification===== Response fields//здесь описание полей ответа===== Example//ну и пример того, что вообще ожидать в ответе

Вот такой документ

87

Page 88: Everything as a code

./gradlew ... asciidoc publishDocs

88

Ну, вы поняли да? :)

Page 89: Everything as a code

def "Rent a hippo"() { given: def request = post("/rent").header("User-ID", "aatarasoff")

when: def result = this.mvc.perform(request)

then: result.andExpect(status().isOk()) .andDo(document( "rent-hippo", preprocessResponse(prettyPrint()), requestHeaders( headerWithName("User-ID").description("User unique identifier")), responseFields( fieldWithPath("hippoRemain").description("Hippo remain count"), fieldWithPath("parrot_fee").description("Fee in virtual parrots"), fieldWithPath("ins").description("Insurance number. Yeah, we sell it"), fieldWithPath("hash").description("Blockchain block hash")) ))}

…и снова тесты

89

Page 90: Everything as a code

def "Rent a hippo"() { given: def request = post("/rent").header("User-ID", "aatarasoff")

when: def result = this.mvc.perform(request)

then: result.andExpect(status().isOk()) .andDo(document( "rent-hippo", preprocessResponse(prettyPrint()), requestHeaders( headerWithName("User-ID").description("User unique identifier")), responseFields( fieldWithPath("hippoRemain").description("Hippo remain count"), fieldWithPath("parrot_fee").description("Fee in virtual parrots"), fieldWithPath("ins").description("Insurance number. Yeah, we sell it"), fieldWithPath("hash").description("Blockchain block hash")) ))}

А не документация ли это?

90

Page 91: Everything as a code

document( "rent-hippo", preprocessResponse(prettyPrint()), requestHeaders( headerWithName("User-ID").description("User unique identifier")), responseFields( fieldWithPath("hippoRemain").description("Hippo remain count"), fieldWithPath("parrot_fee").description("Fee in virtual parrots"), fieldWithPath("ins").description("Insurance number. Yeah, we sell it"), fieldWithPath("hash").description("Blockchain block hash")))

Имя сниппета

91

Page 92: Everything as a code

document( "rent-hippo", preprocessResponse(prettyPrint()), requestHeaders( headerWithName("User-ID").description("User unique identifier")), responseFields( fieldWithPath("hippoRemain").description("Hippo remain count"), fieldWithPath("parrot_fee").description("Fee in virtual parrots"), fieldWithPath("ins").description("Insurance number. Yeah, we sell it"), fieldWithPath("hash").description("Blockchain block hash")))

Тестируем заголовки

92

Page 93: Everything as a code

document( "rent-hippo", preprocessResponse(prettyPrint()), requestHeaders( headerWithName("User-ID").description("User unique identifier")), responseFields( fieldWithPath("hippoRemain").description("Hippo remain count"), fieldWithPath("parrot_fee").description("Fee in virtual parrots"), fieldWithPath("ins").description("Insurance number. Yeah, we sell it"), fieldWithPath("hash").description("Blockchain block hash")))

Тестируем поля ответа

93

Page 94: Everything as a code

generated-snippetsrent-hippo

curl-request.adochttp-request.adochttp-response.adochttpie-request.adocrequest-headers.adocresponse-fields.adoc

Получаем сниппеты

94

Page 95: Everything as a code

= Hippo Rent ServiceThis is documentation for Open API of our hippo renting service

== Methods

=== Rent

==== Request specification===== Headersinclude::{snippets}/rent-hippo/request-headers.adoc[]===== Exampleinclude::{snippets}/rent-hippo/http-request.adoc[]

==== Response specification===== Response fieldsinclude::{snippets}/rent-hippo/response-fields.adoc[]===== Exampleinclude::{snippets}/rent-hippo/http-response.adoc[]

Вставляем их в документ

95

Page 96: Everything as a code

= Hippo Rent ServiceThis is documentation for Open API of our hippo renting service

== Methods

=== Rent

==== Request specification===== Headersinclude::{snippets}/rent-hippo/request-headers.adoc[]===== Exampleinclude::{snippets}/rent-hippo/http-request.adoc[]

==== Response specification===== Response fieldsinclude::{snippets}/rent-hippo/response-fields.adoc[]===== Exampleinclude::{snippets}/rent-hippo/http-response.adoc[]

96

Page 97: Everything as a code

97

Page 98: Everything as a code

Что получили?

● Документация как код

○ лежит в репозитории с кодом

○ встроена в цикл сборки

○ рендерится в html, pdf и т.д.

○ почти всегда актуальна

● Синергия с тестами

98

Page 99: Everything as a code

Инфракод

99

Page 100: Everything as a code

Hardware

Containers

Application

PaaS

Mesos/Kubernetes/Private cloud

100

Page 101: Everything as a code

Hardware + OS System Libs PaaS Application

101

Page 102: Everything as a code

Hardware + OS System Libs PaaS Application

Ansible

102

Page 103: Everything as a code

Hardware + OS System Libs PaaS Application

AnsiblePuppet/Chef

103

Page 104: Everything as a code

Ansible. Inventory

[datacenter]api-server-1api-server-2api-server-3

[datacenter:vars]magicvar = 42

104

Page 105: Everything as a code

Ansible. Playbook

- hosts: datacenter roles: - role: docker - role: rsyslog

105

Page 106: Everything as a code

ansible-playbook -i datacenter1 bootstrap.yml

106

Без комментариев

Page 107: Everything as a code

Hardware + OS System Libs PaaS Application

Ansible

107

Page 108: Everything as a code

Hardware + OS System Libs PaaS Application

AnsiblePuppet/Chef

108

Page 109: Everything as a code

Hardware + OS System Libs PaaS Application

Manifest

109

Page 110: Everything as a code

Docker compose

services: zk: image: zookeeper network_mode: bridge ports: - 2181:2181 environment: ZK_CONFIG: tickTime=2000,initLimit=10,clientPort=2181 ZK_ID: 1

110

Page 111: Everything as a code

Docker compose

services: zk: image: zookeeper network_mode: bridge ports: - 2181:2181 environment: ZK_CONFIG: tickTime=2000,initLimit=10,clientPort=2181 ZK_ID: 1

111

Page 112: Everything as a code

Конфигурация сервиса

services: zk: image: zookeeper network_mode: bridge ports: - 2181:2181 environment: ZK_CONFIG: tickTime=2000,initLimit=10,clientPort=2181 ZK_ID: 1

112

Page 113: Everything as a code

Mesos/Marathon{ "id": "/api/rent-service", "cpus": 1, "mem": 1024, "instances": 3, "container": { "docker": { "image": "rent-service:0.0.1", "portMappings": [ { "containerPort": 8080 } ] } }}

113

Page 114: Everything as a code

curl -X POST ... http://marathon/v2/apps?force=true

114

Вот и весь деплоймент

Page 115: Everything as a code

Конфигурация приложений

https://your_repo/rent-service-config/routes.yml

routes: payment: path: /payment-service/** serviceId: payment-service

115

Page 116: Everything as a code

Ещё конфигурация

● Zookeeper

● Consul

● Vault

● configo by Zeroturnaround

● ...

116

Page 117: Everything as a code

configo

117

docker run \ -e CONFIGO_SOURCE_0='{"type": "http", "format": "yaml", "url":

"https://my.server.com/common.yaml"}' \ rent-service

//внутри приложенияgetEnvironmentVariable("MY_ENV_VAR")

https://github.com/zeroturnaround/configo

Page 118: Everything as a code

Что получили?

● Инфрастуктура может быть легко

описана в виде кода

● Деплоймент и конфигурация

приложений в виде конфигов и

манифестов

118

Page 119: Everything as a code

Неубиваемый CI

119

Page 120: Everything as a code

120

Install Master Configure Slaves

Page 121: Everything as a code

121

Install Master Configure Slaves

Ansible

Page 122: Everything as a code

122

Install Master Configure Slaves

Ansible

Page 123: Everything as a code

Jenkins Docker Cloud plugin

<——— Хост с докером

<——— Сколько контейнеров можно запустить

123

Page 124: Everything as a code

Автоконфигурация

<clouds> {% for group in ['build', 'test', 'production'] %} {% for node in groups[group + '-slaves'] %} <com.github.kostyasha.yad.DockerCloud plugin="[email protected]"> <name>{{ node }}</name>

... <templates> <com.github.kostyasha.yad.DockerSlaveTemplate> <id>mycloud-template</id> <dockerContainerLifecycle> <image>{{ group }}-jenkins-slave</image> ...

</templates> <connector> <serverUrl>tcp://{{ node.hostname }}:2375</serverUrl> <apiVersion>1.20</apiVersion> </connector> </com.github.kostyasha.yad.DockerCloud> {% endfor %} {% endfor %} </clouds>

124

Page 125: Everything as a code

Код доставки

125

Page 126: Everything as a code

126

Page 127: Everything as a code

pipeline-template.groovy

127

Page 128: Everything as a code

//checkout and definition stagenode('build') { // Mark the code checkout 'stage' stage 'Checkout' git credentialsId: 'jenkins-git', url: "${git_url}/${repo}.git"

// Mark build 'stage' stage 'Build'

sh ('./gradlew clean build final')}

//next steps128

Page 129: Everything as a code

//checkout and definition stagenode('build') { // Mark the code checkout 'stage' stage 'Checkout' git credentialsId: 'jenkins-git', url: "${git_url}/${repo}.git"

// Mark build 'stage' stage 'Build'

sh ('./gradlew clean build final')}

//next steps129

Page 130: Everything as a code

//checkout and definition stagenode('build') { // Mark the code checkout 'stage' stage 'Checkout' git credentialsId: 'jenkins-git', url: "${git_url}/${repo}.git"

// Mark build 'stage' stage 'Build'

sh ('./gradlew clean build final')}

//next steps130

Page 131: Everything as a code

//checkout and definition stagenode('build') { // Mark the code checkout 'stage' stage 'Checkout' git credentialsId: 'jenkins-git', url: "${git_url}/${repo}.git"

// Mark build 'stage' stage 'Build'

sh ('./gradlew clean build final')}

//next steps131

Page 132: Everything as a code

//checkout and definition stagenode('build') { // Mark the code checkout 'stage' stage 'Checkout' git credentialsId: 'jenkins-git', url: "${git_url}/${repo}.git"

// Mark build 'stage' stage 'Build'

sh ('./gradlew clean build final')}

//next steps132

Page 133: Everything as a code

//checkout and definition stagenode('build') { // Mark the code checkout 'stage' stage 'Checkout' git credentialsId: 'jenkins-git', url: "${git_url}/${repo}.git"

// Mark build 'stage' stage 'Build'

sh ('./gradlew clean build final')}

//next steps133

Page 134: Everything as a code

//deploy artifact to testnode('test') { sh('ansible-galaxy install -r requirements.yml')

ansiblePlaybook( credentialsId: 'ansible', installation: 'ansible', playbook: 'deploy.yml', inventory: 'test' )}

134

Page 135: Everything as a code

//deploy artifact to testnode('test') { sh('ansible-galaxy install -r requirements.yml')

ansiblePlaybook( credentialsId: 'ansible', installation: 'ansible', playbook: 'deploy.yml', inventory: 'test' )}

135

Page 136: Everything as a code

//deploy artifact to testnode('test') { sh('ansible-galaxy install -r requirements.yml')

ansiblePlaybook( credentialsId: 'ansible', installation: 'ansible', playbook: 'deploy.yml', inventory: 'test' )}

136

Page 137: Everything as a code

//deploy artifact to testnode('test') { sh('ansible-galaxy install -r requirements.yml')

ansiblePlaybook( credentialsId: 'ansible', installation: 'ansible', playbook: 'deploy.yml', inventory: 'test' )}

137

Page 138: Everything as a code

//deploy artifact to testnode('test') { sh('ansible-galaxy install -r requirements.yml')

ansiblePlaybook( credentialsId: 'ansible', installation: 'ansible', playbook: 'deploy.yml', inventory: 'test' )}

jiraComment ( issueKey: issue_id, body: "Artifact has been deployed")

138

Page 139: Everything as a code

node('build') { def repos = fetchRepos(project) for (repo in repos) { build(repo) }}

def fetchRepos(String project) { def url = new URL("https://repo/projects/${project}/repos?limit=1000")

def conn = url.openConnection() conn.setRequestMethod("GET") def responseCode = conn.getResponseCode()

final slurper = new groovy.json.JsonSlurper()

def repos = slurper.parse(conn.getInputStream()).values

for (repo in repos) { if (repo.slug.contains('one-')) result << repo.slug }

return result}

139

Page 140: Everything as a code

node('build') { def repos = fetchRepos(project) for (repo in repos) { build(repo) }}

def fetchRepos(String project) { def url = new URL("https://repo/projects/${project}/repos?limit=1000")

def conn = url.openConnection() conn.setRequestMethod("GET") def responseCode = conn.getResponseCode()

final slurper = new groovy.json.JsonSlurper()

def repos = slurper.parse(conn.getInputStream()).values

for (repo in repos) { if (repo.slug.contains('one-')) result << repo.slug }

return result}

140

Page 141: Everything as a code

node('build') { def repos = fetchRepos(project) for (repo in repos) { build(repo) }}

def fetchRepos(String project) { def url = new URL("https://repo/projects/${project}/repos?limit=1000")

def conn = url.openConnection() conn.setRequestMethod("GET") def responseCode = conn.getResponseCode()

final slurper = new groovy.json.JsonSlurper()

def repos = slurper.parse(conn.getInputStream()).values

for (repo in repos) { if (repo.slug.contains('one-')) result << repo.slug }

return result}

141

Page 142: Everything as a code

Микросервисы

142

Page 143: Everything as a code

143

Install Master Configure Slaves

Create meta job

Ansible

Page 144: Everything as a code

144

Install Master Configure Slaves

Create meta job

AnsiblecURL

Page 145: Everything as a code

145

Install Master Configure Slaves

Create meta job

Create pipelines

Page 146: Everything as a code

jobs.each { job -> pipelineJob("${basePath}/${job}") { //define SCM

definition { cps { script(readFileFromWorkspace('pipeline-template.groovy')) sandbox() } } }}

JobDSL plugin

146

Page 147: Everything as a code

jobs.each { job -> pipelineJob("${basePath}/${job}") { //define SCM

definition { cps { script(readFileFromWorkspace('pipeline-template.groovy')) sandbox() } } }}

JobDSL plugin

147

Page 148: Everything as a code

jobs.each { job -> pipelineJob("${basePath}/${job}") { //define SCM

definition { cps { script(readFileFromWorkspace('pipeline-template.groovy')) sandbox() } } }}

JobDSL plugin

148

Page 149: Everything as a code

149

Install Master Configure Slaves

Create meta job

Create pipelines

git

Page 150: Everything as a code

ansible-playbook -i jenkins-for-my-team jenkins.yml

150

Это последний раз

Page 151: Everything as a code

Что получили?

● Пайплайн как код

● Неубиваемый CI

○ без бэкапов

○ всё хранится как код

○ разворачивается за X минут

151

Page 152: Everything as a code

Выводы

● Почти любой процесс можно

формализовать, представить в

виде кода и автоматизировать

● Мы все пишем код, хотя можем

думать, что это не так

152

Page 153: Everything as a code

Спасибо, что выбрали красную

Page 154: Everything as a code

@aatarasoff

@aatarasoff

@aatarasoff

QA