SlideShare a Scribd company logo
Everything as a Code
Непривычно о привычном
@aatarasoff
@aatarasoff
@aatarasoff
Everything as a Code
Непривычно о привычном
No warranty guarantee
You think you are creator
5
6
… but matrix has you
7
Выйти за пределы...
8
...поняв, что всё есть код
9
Как вы представляете себе код?
10
@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;
}
}
11
Наверное как-то так
>>,[>>,]<<[
[<<]>>>>[
<<[>+<<+>-]
>>[>+<<<<[->]>[<]>>-]
<<<[[-]>>[>+<-]>>[<<<+>>>-]]
>>[[<+>-]>>]<
]<<[>>+<<-]<<
]>>>>[.>>]
12
...или может быть так?
Что такое код?
● Коллекция инструкций
● Человекочитаемый формат
○ plain text
● Может быть понят и “проигран”
○ после компиляции
○ интерпретатором
13
Да я тоже пишу код!
14
Вооружи себя
15
Настройка рабочего окружения
16
Install apps Code Checkout
Configure
workspace
First Blood
17
Install apps Code Checkout
Configure
workspace
First Blood
brew install
18
Install apps Code Checkout
Configure
workspace
First Blood
brew install
pip install
19
Install apps Code Checkout
Configure
workspace
First Blood
git
20
Install apps Code Checkout
Configure
workspace
First Blood
customize
*.properties
21
Install apps Code Checkout
Configure
workspace
First Blood
customize
*.propertiestemplate
.gradle
22
Install apps Code Checkout
Configure
workspace
First Blood
customize
*.properties
install
certificates
23
Install apps Code Checkout
Configure
workspace
First Blood
first build
24
Install apps Code Checkout
Configure
workspace
First Blood
mass build
first deploy
25
ansible-playbook -i local-inv setup.yml --tags configure
26
Интерпретатор
ansible-playbook -i local-inv setup.yml --tags configure
27
Конфигурация
ansible-playbook -i local-inv setup.yml --tags configure
28
Алгоритм
# 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: deploy.yml
29
Алгоритм
ansible-playbook -i local-inv setup.yml --tags configure
30
Входные параметры
- name: checkout services
git:
repo: "{{ git.root }}/{{ item.name }}.git"
dest: "{{ work_dir }}/{{ item.name }}"
update: yes
with_items:
- "{{ services }}"
tags:
- services
31
Массовый checkout/pull
- name: checkout services
git:
repo: "{{ git.root }}/{{ item.name }}.git"
dest: "{{ work_dir }}/{{ item.name }}"
update: yes
with_items:
- "{{ services }}"
tags:
- services
Переменные
32
- 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 }
Циклы
33
services:
- { name: one-instant-messenger, sourceDir: src }
- { name: one-discussions, sourceDir: src }
- { name: one-attachment, sourceDir: src, testDir: test }
Коллекции и структуры данных
34
- 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
Шаблоны
35
{% 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 %}
}
Условные операторы
36
{% 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 %}
}
Опять циклы
37
{% 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 %}
}
Переменные
38
- stat: path={{ username }}.key
register: certkey
- name: generate private key
shell: openssl genrsa -out {{ username }}.key -aes256 4096
when: not certkey.stat.exists
Идемпотентность
39
Install apps Code Checkout
Configure
workspace
Multiplie Use
40
Петля обратной связи
git
Что получили
● Автоконфигурация рабочего
пространства
○ повторяемая
○ немутабельная
● Можно дать скрипт новичку
● Можно и нужно пользоваться этим
каждый день
41
Код есть код
42
Искусство сборки
43
Compile code Unit tests Package Publishing
44
Compile code Unit tests Package
compiler
Publishing
45
Compile code Unit tests Package
javacresource
processing
Publishing
46
Compile code Unit tests Package
javacresources
copyingdependency
resolving
Publishing
47
Compile code Unit tests Package
junit
Publishing
48
Compile code Unit tests Package
jar
Publishing
49
Compile code Unit tests Package
jar
npm, deb, ...
Publishing
50
Compile code Unit tests Package
jar
npm, so, ...
docker image
Publishing
51
Compile code Unit tests Package
ivy
Publishing
52
Compile code Unit tests Package
maven, ivy
maven
Publishing
53
Compile code Unit tests Package Publishing
maven, ivylocal or dev
deploydocker registry
54
Системы сборки
● Ant + Ivy
● Maven
● Gradle
● Docker
● npm
● ...
55
FROM golang:1.7-alpine
MAINTAINER aatarasoff@gmail.com
VOLUME /data
WORKDIR /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. Наследование
56
FROM golang:1.7-alpine
MAINTAINER aatarasoff@gmail.com
VOLUME /data
WORKDIR /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. Инструкции
57
FROM golang:1.7-alpine
MAINTAINER aatarasoff@gmail.com
ARG maindir=/data
VOLUME $maindir
WORKDIR $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. Переменные
58
docker build … && docker push …
59
publishing {
publications {
mavenJava(MavenPublication) {
artifactId 'spring-one-nio-autoconfigure'
from components.java
artifact sourceJar {
classifier "sources"
}
}
}
}
Gradle. DSL
60
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. Код как он есть
61
<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-е есть жизнь
62
./gradlew build test ant-docker-build-image publish
63
Фреймворки
для автоматизации
● Ant + Ivy
● Maven
● Gradle
● Docker
● npm
● ...
64
Что получили
● Сборка это код
○ XML
○ DSL
○ Groovy
○ etc
● Системы сборки не только для
сборки
65
Ликвидация багов
66
Unit tests API tests Stress tests UI tests
67
Unit tests API tests Stress tests UI tests
TDD
68
goss --vars vars.yaml validate
69
port:
tcp:5601:
listening: true
ip:
- 0.0.0.0
service:
mesosd:
enabled: true
running: true
goss.yml
70
port:
tcp:5601:
listening: true
ip:
- 0.0.0.0
service:
mesosd:
enabled: true
running: true
goss.yml
71
port:
tcp:5601:
listening: true
ip:
- 0.0.0.0
service:
mesosd:
enabled: true
running: true
goss.yml
72
Unit tests API tests Stress tests UI tests
BDD Specs
73
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
74
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"))
}
Простые проверки
75
Unit tests API tests Stress tests UI tests
JMeter, wrk,
vegeta
76
Unit tests API tests Stress tests UI tests
JMeter
production
77
> config | run command
> echo $?
{0,1}
0 - success
1 - error
78
Экспресс-тест
{
"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
79
{
"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
80
{
"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
81
cat config.json | docker run -i apistress -config=stdin
82
Где-то мы такое видели
https://github.com/aatarasoff/apistress
Requests [total, rate] 50, 10.20
Duration [total, attack, wait] 5.022872793s, 4.899943287s, 122.929506ms
Latencies [mean, 50, 95, 99, max] 143.772484ms, ..., 290.101831ms
Bytes In [total, mean] 4842, 96.84
Bytes Out [total, mean] 950, 19.00
Success [ratio] 100.00%
Status Codes [code:count] 200:50
Error Set:
Test#1
83
Requests [total, rate] 50, 10.20
Duration [total, attack, wait] 5.022872793s, 4.899943287s, 122.929506ms
Latencies [mean, 50, 95, 99, max] 143.772484ms, ..., 290.101831ms
Bytes In [total, mean] 4842, 96.84
Bytes Out [total, mean] 950, 19.00
Success [ratio] 100.00%
Status Codes [code:count] 200:50
Error Set:
Test#1
84
attacker := vegeta.NewAttacker()
var metrics vegeta.Metrics
for res := range attacker.Attack(targeter, rate, duration) {
metrics.Add(res)
}
metrics.Close()
if metrics.Success*100 < test.SLA.SuccessRate {
os.Exit(1)
}
if metrics.Latencies.P99() > SLA.Latency*time.Millisecond.Nanoseconds() {
os.Exit(1)
}
Немного go-кода
85
attacker := vegeta.NewAttacker()
var metrics vegeta.Metrics
for res := range attacker.Attack( targeter, rate, duration) {
metrics.Add(res)
}
metrics.Close()
if metrics.Success*100 < test.SLA.SuccessRate {
os.Exit(1)
}
if metrics.Latencies.P99() > SLA.Latency*time.Millisecond.Nanoseconds() {
os.Exit(1)
}
Майним метрики
86
attacker := vegeta.NewAttacker()
var metrics vegeta.Metrics
for res := range attacker.Attack(targeter, rate, duration) {
metrics.Add(res)
}
metrics.Close()
if metrics.Success*100 < test.SLA.SuccessRate {
os.Exit(1)
}
if metrics.Latencies.P99() > SLA.Latency*time.Millisecond.Nanoseconds() {
os.Exit(1)
}
Не слишком ли много ошибок?
87
attacker := vegeta.NewAttacker()
var metrics vegeta.Metrics
for res := range attacker.Attack(targeter, rate, duration) {
metrics.Add(res)
}
metrics.Close()
if metrics.Success*100 < test.SLA.SuccessRate {
os.Exit(1)
}
if metrics.Latencies.P99() > SLA.Latency*time.Millisecond.Nanoseconds() {
os.Exit(1)
}
Уложились ли по времени?
88
> cat config.json | docker run -i apistress -config=stdin
> echo $?
0
89
Код возврата
Requests [total, rate] 200, 10.05
Duration [total, attack, wait] 23.04784s, 19.899754743s, 3.148093811s
Latencies [mean, 50, 95, 99, max] 3.023677499s, ..., 11.832287083s
Bytes In [total, mean] 6874, 34.37
Bytes Out [total, mean] 1349, 6.75
Success [ratio] 35.50%
Status Codes [code:count] 0:129 200:71
Error Set:
Get http://host:9000/rent-service/rent: EOF
Get http://host:9000/rent-service/rent: http: server closed idle connection
...
Test#2
90
> cat config.json | docker run -i apistress -config=stdin
> echo $?
1
91
Код возврата
Unit tests API tests Stress tests UI tests
Selenium,
Selenide
92
Что получили
● Все тестовые сценарии в коде
● Можно встроить в процесс сборки
или доставки ПО
● Если хотите, то можно
генерировать отчёты для разбора
полётов
93
Эксперименты
94
Code Branches
95
if / switch
Code Branches
96
if / switch
DI
Code Branches
97
if / switch
DI
API v2
ISupplier<String, Ctx> srcsetSupplier = (ctx) -> {
if (configuration. isDoubleDensityAvatarsEnabled(user.getModel())) {
String link = imageSrc.getModel();
return linkBuilder.createSourceSetLink(link);
}
return "";
};
Очень простой эксперимент
98
Code Branches
One server or
partition
99
//by partition
app.photos.doubleDensityAvatarsEnabled: 0
Step#1
Code Branches
One server or
partition
Part of servers
or partitions
100
//by partition
app.photos.doubleDensityAvatarsEnabled: 0,4,7-9
Step#1 Step#2
Code Branches
One server or
partition
Part of servers
or partitions
All servers or
partitions
101
//by partition
app.photos.doubleDensityAvatarsEnabled: ALL
Step#1 Step#2 Step#3
//step#1
app.photos.doubleDensityAvatarsEnabled: 0
//step#2
app.photos.doubleDensityAvatarsEnabled: 0,4,7-9
//step#3
app.photos.doubleDensityAvatarsEnabled: ALL
102
Очень простой эксперимент
No one
One server or
partition
Part of servers
or partitions
All servers or
partitions
103
monitor
Step#1 Step#2 Step#3Step#0
104
Что хотим?
ansible-playbook -i {dev,test,prod}-env exp.yml --tags stepN
105
Абстракция
- name: update properties
uri:
url: "http://{{ pms_host }}/api/conf/update"
method: POST
user: "{{ username }}"
password: "{{ password }}"
force_basic_auth: yes
body:
applicationName: "{{ application_name }}"
propertyName: "{{ item.value.name }}"
propertyValue: "{{ item.value.value }}"
body_format: json
status_code: 200
headers:
Content-Type: "application/json"
with_dict: "{{ properties }}"
106
Координаты
- name: update properties
uri:
url: "http://{{ pms_host }}/api/conf/update"
method: POST
user: "{{ username }}"
password: "{{ password }}"
force_basic_auth: yes
body:
applicationName: "{{ application_name }}"
propertyName: "{{ item.value.name }}"
propertyValue: "{{ item.value.value }}"
body_format: json
status_code: 200
headers:
Content-Type: "application/json"
with_dict: "{{ properties }}"
107
Вкатываем настройки
- name: update properties
uri:
url: "http://{{ pms_host }}/api/conf/update"
method: POST
user: "{{ username }}"
password: "{{ password }}"
force_basic_auth: yes
body:
applicationName: "{{ application_name }}"
propertyName: "{{ item.value.name }}"
propertyValue: "{{ item.value.value }}"
body_format: json
status_code: 200
headers:
Content-Type: "application/json"
with_dict: "{{ properties }}"
108
Проверяем корректность
- name: update properties
uri:
url: "http://{{ pms_host }}/api/conf/update"
method: POST
user: "{{ username }}"
password: "{{ password }}"
force_basic_auth: yes
body:
applicationName: "{{ application_name }}"
propertyName: "{{ item.value.name }}"
propertyValue: "{{ item.value.value }}"
body_format: json
status_code: 200
headers:
Content-Type: "application/json"
with_dict: "{{ properties }}"
109
Step#0
- hosts: local
vars:
application_name: odnoklassniki-web
props:
doubleDensityAvatarsEnabled:
name: "app.photos.doubleDensityAvatarsEnabled"
value: ""
roles:
- { name: pms, properties: "{{ props }}" }
110
Step#0
- hosts: local
vars:
application_name: odnoklassniki-web
props:
doubleDensityAvatarsEnabled:
name: "app.photos.doubleDensityAvatarsEnabled"
value: ""
roles:
- { name: pms, properties: "{{ props }}" }
111
Step#1
- hosts: local
vars:
application_name: odnoklassniki-web
props:
doubleDensityAvatarsEnabled:
name: "app.photos.doubleDensityAvatarsEnabled"
value: "0"
roles:
- { name: pms, properties: "{{ props }}" }
112
Step#2
- hosts: local
vars:
application_name: odnoklassniki-web
props:
doubleDensityAvatarsEnabled:
name: "app.photos.doubleDensityAvatarsEnabled"
value: "0,4,7-9"
roles:
- { name: pms, properties: "{{ props }}" }
113
Step#3
- hosts: local
vars:
application_name: odnoklassniki-web
props:
doubleDensityAvatarsEnabled:
name: "app.photos.doubleDensityAvatarsEnabled"
value: "ALL"
roles:
- { name: pms, properties: "{{ props }}" }
114
exp.yml
---
- include: step0.yml
tags:
- step0
- cleanup
- include: step1.yml
tags: step1
- include: step2.yml
tags: step2
- include: step3.yml
tags:
- step3
- complete
Что получили
● Эксперименты хранятся в git-
репозитории
● Можно применить любой шаг в
любой момент времени на любой
среде
● Можно встроить в пайплайн
доставки
115
Кододокументация
116
Analyst, PM Developer Tester Docs
Word, PDF...
117
Analyst, PM Developer Tester Docs
Word, PDF... Code + Tests
118
Analyst, PM Developer Tester Docs
Word, PDF... Code + Tests Test cases
119
Analyst, PM Developer Tester Docs :(
Word, PDF... Code + Tests Test cases
120
Analyst, PM Developer Tester Docs :)
Markdown/Asciidoctor
Docs :)
121
= Hippo Rent Service
This is documentation for Open API of our hippo renting service
== Methods
=== Rent
==== Request specification
===== Headers
//тут опишем http-заголовки
===== Example
//а здесь будут примеры вызова
==== Response specification
===== Response fields
//здесь описание полей ответа
===== Example
//ну и пример того, что вообще ожидать в ответе
Вот такой документ
122
./gradlew ... asciidoc publishDocs
123
Компиляция документа
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"))
))
}
…и снова тесты
124
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"))
))
}
А не документация ли это?
125
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"))
)
Имя сниппета
126
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"))
)
Тестируем заголовки
127
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"))
)
Тестируем поля ответа
128
generated-snippets
rent-hippo
curl-request.adoc
http-request.adoc
http-response.adoc
httpie-request.adoc
request-headers.adoc
response-fields.adoc
Получаем сниппеты
129
= Hippo Rent Service
This is documentation for Open API of our hippo renting service
== Methods
=== Rent
==== Request specification
===== Headers
include::{snippets}/rent-hippo/request-headers.adoc[]
===== Example
include::{snippets}/rent-hippo/http-request.adoc[]
==== Response specification
===== Response fields
include::{snippets}/rent-hippo/response-fields.adoc[]
===== Example
include::{snippets}/rent-hippo/http-response.adoc[]
Вставляем их в документ
130
= Hippo Rent Service
This is documentation for Open API of our hippo renting
service
== Methods
=== Rent
==== Request specification
===== Headers
include::{snippets}/rent-hippo/request-headers.adoc[]
===== Example
include::{snippets}/rent-hippo/http-request.adoc[]
==== Response specification
===== Response fields
include::{snippets}/rent-hippo/response-fields.adoc[]
===== Example
include::{snippets}/rent-hippo/http-response.adoc[]
131
132
Что получили?
● Документация как код
○ лежит в репозитории с кодом
○ встроена в цикл сборки
○ рендерится в html, pdf и т.д.
○ почти всегда актуальна
● Синергия с тестами
133
Инфракод
134
Hardware
Containers
Application
PaaS
Mesos/Kubernetes/Private cloud
135
Hardware + OS System Libs PaaS Application
136
Hardware + OS System Libs PaaS Application
Ansible
137
Hardware + OS System Libs PaaS Application
Ansible
Puppet/Chef
138
Ansible. Inventory
[datacenter]
api-server-1
api-server-2
api-server-3
[datacenter:vars]
magicvar = 42
139
Ansible. Playbook
- hosts: datacenter
roles:
- role: docker
- role: rsyslog
140
ansible-playbook -i dc1 bootstrap.yml
141
Без комментариев
Hardware + OS System Libs PaaS Application
Ansible
142
Hardware + OS System Libs PaaS Application
Ansible
Puppet/Chef
143
Hardware + OS System Libs PaaS Application
Manifest
144
Docker compose
services:
zk:
image: zookeeper
network_mode: bridge
ports:
- 2181:2181
environment:
ZK_CONFIG: tickTime=2000,initLimit=10,clientPort=2181
ZK_ID: 1
145
Docker compose
services:
zk:
image: zookeeper
network_mode: bridge
ports:
- 2181:2181
environment:
ZK_CONFIG: tickTime=2000,initLimit=10,clientPort=2181
ZK_ID: 1
146
Конфигурация сервиса
services:
zk:
image: zookeeper
network_mode: bridge
ports:
- 2181:2181
environment:
ZK_CONFIG: tickTime=2000,initLimit=10,clientPort=2181
ZK_ID: 1
147
Mesos/Marathon
{
"id": "/api/rent-service",
"cpus": 1,
"mem": 1024,
"instances": 3,
"container": {
"docker": {
"image": "rent-service:0.0.1",
"portMappings": [
{
"containerPort": 8080
}
]
}
}
}
148
curl -X POST ... http://marathon/v2/apps?force=true
149
Современный деплоймент
Конфигурация приложений
https://your_repo/rent-service-config/routes.yml
routes:
payment:
path: /payment-service/**
serviceId: payment-service
150
Ещё конфигурация
● Zookeeper
● Consul
● Vault
● configo
● ...
151
configo
152
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/bsideup/configo
configo
153
docker run 
-e CONFIGO_SOURCE_0='{"type": "http", "format": "yaml", "url":
"https://my.server.com/common.yaml"}' 
-e CONFIGO_SOURCE_1='{"type" : "consul",
"address": "consul.master:8500",
"prefix" : "common"}' 
rent-service
//внутри приложения
getEnvironmentVariable("MY_ENV_VAR")
https://github.com/bsideup/configo
Что получили?
● Инфрастуктура может быть легко
описана в виде кода
● Деплоймент и конфигурация
приложений в виде конфигов и
манифестов
154
Неубиваемый CI
155
156
Install Master
Configure
Slaves
157
Install Master
Configure
Slaves
Ansible
158
Install Master
Configure
Slaves
Ansible
Jenkins Docker Cloud plugin
<——— Хост с докером
<——— Сколько контейнеров можно запустить
159
Автоконфигурация
<clouds>
{% for group in ['build', 'test', 'production'] %}
{% for node in groups[group + '-slaves'] %}
<com.github.kostyasha.yad.DockerCloud plugin="yet-another-docker-plugin@0.1.0-rc31">
<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>
160
Код доставки
161
Everything as a code
Everything as a code
//checkout and definition stage
node('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 steps
//checkout and definition stage
node('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 steps
//checkout and definition stage
node('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 steps
//checkout and definition stage
node('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 steps
//checkout and definition stage
node('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 steps
//checkout and definition stage
node('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 steps
//deploy artifact to test
node('test') {
sh('ansible-galaxy install -r requirements.yml')
ansiblePlaybook(
credentialsId: 'ansible',
installation: 'ansible',
playbook: 'deploy.yml',
inventory: 'test'
)
}
//deploy artifact to test
node('test') {
sh('ansible-galaxy install -r requirements.yml')
ansiblePlaybook(
credentialsId: 'ansible',
installation: 'ansible',
playbook: 'deploy.yml',
inventory: 'test'
)
}
//deploy artifact to test
node('test') {
sh('ansible-galaxy install -r requirements.yml')
ansiblePlaybook(
credentialsId: 'ansible',
installation: 'ansible',
playbook: 'deploy.yml',
inventory: 'test'
)
}
//deploy artifact to test
node('test') {
sh('ansible-galaxy install -r requirements.yml')
ansiblePlaybook(
credentialsId: 'ansible',
installation: 'ansible',
playbook: 'deploy.yml',
inventory: 'test'
)
}
//deploy artifact to test
node('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"
)
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
}
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
}
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
}
Микросервисы
178
179
Install Master
Configure
Slaves
Create
meta job
Ansible
180
Install Master
Configure
Slaves
Create
meta job
Ansible
cURL
181
Install Master
Configure
Slaves
Create
meta job
Create
pipelines
jobs.each { job ->
pipelineJob("${basePath}/${job}") {
//define SCM
definition {
cps {
script(readFileFromWorkspace('pipeline-template.groovy'))
sandbox()
}
}
}
}
JobDSL plugin
182
jobs.each { job ->
pipelineJob("${basePath}/${job}") {
//define SCM
definition {
cps {
script(readFileFromWorkspace('pipeline-template.groovy'))
sandbox()
}
}
}
}
JobDSL plugin
183
jobs.each { job ->
pipelineJob("${basePath}/${job}") {
//define SCM
definition {
cps {
script(readFileFromWorkspace('pipeline-template.groovy'))
sandbox()
}
}
}
}
JobDSL plugin
184
185
Install Master
Configure
Slaves
Create
meta job
Create
pipelines
git
ansible-playbook -i jenkins-for-my-team jenkins.yml
186
Это последний раз
Что получили?
● Пайплайн как код
● Неубиваемый CI
○ без бэкапов
○ всё хранится как код
○ разворачивается за X минут
187
Development Testing Deployment
Post
Deployment
188
> ./gradlew build test
Development Testing Deployment
Post
Deployment
189
> ./gradlew integrationTest publishDocs
Development Testing Deployment
Post
Deployment
190
> ansible-playbook -i env deploy.yml
Development Testing Deployment
Post
Deployment
191
> ansible-playbook -i prod exp.yml
Development Testing Deployment
Post
Deployment
192
Delivery Pipeline
193
Позитивные выводы
● Почти любой процесс можно
формализовать, представить в
виде кода и автоматизировать
● Мы все пишем код, хотя можем
думать, что это не так
● Рано или поздно всё превращается
в код
194
Trade-offs
● Необходимы как разовые
“капиталовложения”, так и
постоянные затраты ресурсов
● Могут потребоваться изменения в
архитектуре
● Требует дисциплины и более
высокой квалификации
специалистов
195
Спасибо, что выбрали красную
@aatarasoff
@aatarasoff
@aatarasoff
QA

More Related Content

PDF
Service Discovery. Spring Cloud Internals
PDF
Docker In Bank Unrated
PDF
Docker In the Bank
PPTX
Js tacktalk team dev js testing performance
PDF
Managing user's data with Spring Session
PDF
We Are All Testers Now: The Testing Pyramid and Front-End Development
PDF
Gradle build tool that rocks with DSL JavaOne India 4th May 2012
PDF
Integration tests: use the containers, Luke!
Service Discovery. Spring Cloud Internals
Docker In Bank Unrated
Docker In the Bank
Js tacktalk team dev js testing performance
Managing user's data with Spring Session
We Are All Testers Now: The Testing Pyramid and Front-End Development
Gradle build tool that rocks with DSL JavaOne India 4th May 2012
Integration tests: use the containers, Luke!

What's hot (20)

PDF
Java EE 6 CDI Integrates with Spring & JSF
PDF
OrientDB - The 2nd generation of (multi-model) NoSQL
PDF
Gradle in 45min
PDF
Springを用いた社内ライブラリ開発
PPTX
Spring & Hibernate
PDF
How and Why Prometheus' New Storage Engine Pushes the Limits of Time Series D...
PDF
Javascript TDD with Jasmine, Karma, and Gulp
PPTX
PPTX
Taking Jenkins Pipeline to the Extreme
PDF
Inria Tech Talk : Comment améliorer la qualité de vos logiciels avec STAMP
PDF
Composable and streamable Play apps
PDF
Using the Groovy Ecosystem for Rapid JVM Development
PDF
Cool JVM Tools to Help You Test
PDF
Gradle Introduction
PDF
Testcontainers - Geekout EE 2017 presentation
PDF
Gradle in 45min - JBCN2-16 version
PDF
10 Cool Facts about Gradle
PDF
Take Control of your Integration Testing with TestContainers
PPTX
Java Libraries You Can’t Afford to Miss
PDF
Cool Jvm Tools to Help you Test - Aylesbury Testers Version
Java EE 6 CDI Integrates with Spring & JSF
OrientDB - The 2nd generation of (multi-model) NoSQL
Gradle in 45min
Springを用いた社内ライブラリ開発
Spring & Hibernate
How and Why Prometheus' New Storage Engine Pushes the Limits of Time Series D...
Javascript TDD with Jasmine, Karma, and Gulp
Taking Jenkins Pipeline to the Extreme
Inria Tech Talk : Comment améliorer la qualité de vos logiciels avec STAMP
Composable and streamable Play apps
Using the Groovy Ecosystem for Rapid JVM Development
Cool JVM Tools to Help You Test
Gradle Introduction
Testcontainers - Geekout EE 2017 presentation
Gradle in 45min - JBCN2-16 version
10 Cool Facts about Gradle
Take Control of your Integration Testing with TestContainers
Java Libraries You Can’t Afford to Miss
Cool Jvm Tools to Help you Test - Aylesbury Testers Version
Ad

Viewers also liked (20)

PDF
Think Like a 50s Ad Exec & Execute Like a Geek #BeWizard
PDF
Artificial Intelligence or the Brainization of the Economy
PPT
Head injury
PPT
Humantalents soft skills training-brochure
PDF
Frameworks We Live By: Design by day-to-day framework development: Multi-para...
PPTX
Splunk Überblick
PPTX
Bilmök 2017 - Microsoft Yeni Yesil Yazilim Geliştirme Teknolojileri
PDF
A Survey of IT Jobs in the Kingdom of Saudi Arabia 2017
PPT
Mr. Ludo Diels IEWP @ 2nd India-EU Water Forum @ World Sustainable Developmen...
PPTX
MongoDB and DigitalOcean Automation with Cloud Manager
PDF
Final seminar on its
PPTX
Dealing with Performance in SharePoint Server
PPTX
Schematic diagrams of GPUs' architecture and Time evolution of theoretical FL...
PDF
NV Wim Delvoye blijft winstmachine
DOC
Investeringsprogramma koninklijk paleis in hoogste versnelling
PPTX
ジャパリパークさいかいけーかく
PPTX
Delfina Gómez, la candidata desconocida
PPTX
Top 10 Digital Workplace Patterns #spscalgary
PDF
マイクロソフトが創る未来 医療編 20170401
PPTX
10 Ways to Validate Your Startup Ideas!
Think Like a 50s Ad Exec & Execute Like a Geek #BeWizard
Artificial Intelligence or the Brainization of the Economy
Head injury
Humantalents soft skills training-brochure
Frameworks We Live By: Design by day-to-day framework development: Multi-para...
Splunk Überblick
Bilmök 2017 - Microsoft Yeni Yesil Yazilim Geliştirme Teknolojileri
A Survey of IT Jobs in the Kingdom of Saudi Arabia 2017
Mr. Ludo Diels IEWP @ 2nd India-EU Water Forum @ World Sustainable Developmen...
MongoDB and DigitalOcean Automation with Cloud Manager
Final seminar on its
Dealing with Performance in SharePoint Server
Schematic diagrams of GPUs' architecture and Time evolution of theoretical FL...
NV Wim Delvoye blijft winstmachine
Investeringsprogramma koninklijk paleis in hoogste versnelling
ジャパリパークさいかいけーかく
Delfina Gómez, la candidata desconocida
Top 10 Digital Workplace Patterns #spscalgary
マイクロソフトが創る未来 医療編 20170401
10 Ways to Validate Your Startup Ideas!
Ad

Similar to Everything as a code (13)

PDF
Кирилл Толкачев. Микросервисы: огонь, вода и девопс
PDF
Everything-as-code: DevOps und Continuous Delivery aus Sicht des Entwicklers.
PDF
Everything-as-code: DevOps und Continuous Delivery aus Sicht des Entwicklers....
PDF
Everything-as-code - A polyglot adventure
PDF
Everything-as-code. A polyglot adventure. #DevoxxPL
PDF
My best grunt
PDF
Everything-as-code - a polyglot journey.
PDF
Everything-as-code. A polyglot journey.
PPTX
Scaling Development Environments with Docker
PDF
Gradle - time for a new build
PDF
In the Brain of Hans Dockter: Gradle
PDF
Gradleintroduction 111010130329-phpapp01
PDF
Everything-as-code – Polyglotte Entwicklung in der Praxis
Кирилл Толкачев. Микросервисы: огонь, вода и девопс
Everything-as-code: DevOps und Continuous Delivery aus Sicht des Entwicklers.
Everything-as-code: DevOps und Continuous Delivery aus Sicht des Entwicklers....
Everything-as-code - A polyglot adventure
Everything-as-code. A polyglot adventure. #DevoxxPL
My best grunt
Everything-as-code - a polyglot journey.
Everything-as-code. A polyglot journey.
Scaling Development Environments with Docker
Gradle - time for a new build
In the Brain of Hans Dockter: Gradle
Gradleintroduction 111010130329-phpapp01
Everything-as-code – Polyglotte Entwicklung in der Praxis

More from Aleksandr Tarasov (10)

PDF
Cocktail of Environments. How to Mix Test and Development Environments and St...
PPTX
Service Discovery. More that it seems
PDF
Continuous Delivery with Jenkins: Lessons Learned
PDF
WILD microSERVICES v2 (JEEConf Edition)
PDF
WILD microSERVICES v2
PDF
Расширь границы возможного вместе с Gradle
PDF
Jbreak 2016: Твой личный Spring Boot Starter
PDF
Хипстеры в энтерпрайзе
PDF
микроСЕРВИСЫ: огонь, вода и медные трубы
PDF
Joker 2015. WILD microSERVICES
Cocktail of Environments. How to Mix Test and Development Environments and St...
Service Discovery. More that it seems
Continuous Delivery with Jenkins: Lessons Learned
WILD microSERVICES v2 (JEEConf Edition)
WILD microSERVICES v2
Расширь границы возможного вместе с Gradle
Jbreak 2016: Твой личный Spring Boot Starter
Хипстеры в энтерпрайзе
микроСЕРВИСЫ: огонь, вода и медные трубы
Joker 2015. WILD microSERVICES

Recently uploaded (20)

PDF
August Patch Tuesday
PDF
A comparative study of natural language inference in Swahili using monolingua...
PDF
Machine learning based COVID-19 study performance prediction
PDF
Spectral efficient network and resource selection model in 5G networks
PDF
Network Security Unit 5.pdf for BCA BBA.
PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
Assigned Numbers - 2025 - Bluetooth® Document
PDF
MIND Revenue Release Quarter 2 2025 Press Release
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PDF
A comparative analysis of optical character recognition models for extracting...
PPTX
TechTalks-8-2019-Service-Management-ITIL-Refresh-ITIL-4-Framework-Supports-Ou...
PDF
Heart disease approach using modified random forest and particle swarm optimi...
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PPTX
Group 1 Presentation -Planning and Decision Making .pptx
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PPTX
OMC Textile Division Presentation 2021.pptx
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PDF
Getting Started with Data Integration: FME Form 101
August Patch Tuesday
A comparative study of natural language inference in Swahili using monolingua...
Machine learning based COVID-19 study performance prediction
Spectral efficient network and resource selection model in 5G networks
Network Security Unit 5.pdf for BCA BBA.
Programs and apps: productivity, graphics, security and other tools
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Assigned Numbers - 2025 - Bluetooth® Document
MIND Revenue Release Quarter 2 2025 Press Release
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
Mobile App Security Testing_ A Comprehensive Guide.pdf
A comparative analysis of optical character recognition models for extracting...
TechTalks-8-2019-Service-Management-ITIL-Refresh-ITIL-4-Framework-Supports-Ou...
Heart disease approach using modified random forest and particle swarm optimi...
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Group 1 Presentation -Planning and Decision Making .pptx
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
OMC Textile Division Presentation 2021.pptx
Advanced methodologies resolving dimensionality complications for autism neur...
Getting Started with Data Integration: FME Form 101

Everything as a code