ΠΠΌΠ° ΠΌΠ½ΠΎΠ³Ρ Π½Π°ΠΏΠΈΡΠΈ Π½Π° Π₯Π°Π±ΡΠ΅ Π·Π° ΠΠ΅Π½ΠΊΠΈΠ½Ρ, Π½ΠΎ ΠΌΠ°Π»ΠΊΡΠΌΠΈΠ½Π° ΠΎΠΏΠΈΡΡΠ²Π°Π°Ρ ΠΏΡΠΈΠΌΠ΅ΡΠΈ Π·Π° ΡΠΎΠ° ΠΊΠ°ΠΊΠΎ ΡΡΠ½ΠΊΡΠΈΠΎΠ½ΠΈΡΠ°Π°Ρ ΠΠ΅Π½ΠΊΠΈΠ½Ρ ΠΈ Π΄ΠΎΠΊΠ΅ΡΡΠΊΠΈΡΠ΅ Π°Π³Π΅Π½ΡΠΈ. Π‘ΠΈΡΠ΅ ΠΏΠΎΠΏΡΠ»Π°ΡΠ½ΠΈ Π°Π»Π°ΡΠΊΠΈ Π·Π° ΠΈΠ·Π³ΡΠ°Π΄Π±Π° Π½Π° ΠΏΡΠΎΠ΅ΠΊΡΠΈ ΠΊΠ°ΠΊΠΎ
ΠΠ΅Π½Π΅Ρ ΠΈΠΌΠ° ΡΠ΅ΡΠ΅Π½ΠΈΠ΅ Π·Π° ΠΏΡΠΎΠ±Π»Π΅ΠΌΠΎΡ: ΠΠ΅Π½ΠΊΠΈΠ½Ρ 2 ΠΎΠ΄Π»ΠΈΡΠ½ΠΎ ΡΠ°Π±ΠΎΡΠΈ ΡΠΎ Π½Π΅Π³ΠΎ
ΠΠΎΡΡΠΎ ΠΏΠΎΡΠ½Π°Π² Π΄Π° Π³ΠΎ ΡΠ΅ΡΠ°Π²Π°ΠΌ ΠΎΠ²ΠΎΡ ΠΏΡΠΎΠ±Π»Π΅ΠΌ?
ΠΠΈΠ΄Π΅ΡΡΠΈ ΡΠΌΠ΅ Π²ΠΎ Π΄ΡΡΡΡΠ²ΠΎ
- Π³ΠΎΠ»Π΅ΠΌΠ° ΠΊΠΎΠ»ΠΈΡΠΈΠ½Π° Π½Π° ΡΡΠ°Π΅ΡΠ΅ ΡΡΠΎ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠ΅ΡΠΈΡΠ΅ Π·Π°Π±ΠΎΡΠ°Π²Π°Π°Ρ Π΄Π° Π³ΠΎ ΠΈΡΡΠΈΡΡΠ°Ρ;
- ΠΈΠΌΠ° ΠΊΠΎΠ½ΡΠ»ΠΈΠΊΡΠΈ ΠΏΠΎΠΌΠ΅ΡΡ ΡΠ°Π·Π»ΠΈΡΠ½ΠΈ Π²Π΅ΡΠ·ΠΈΠΈ Π½Π° ΠΈΡΡΠΎ Π²ΡΠ΅ΠΌΠ΅ Π½Π° ΡΡΠ°Π΅ΡΠ΅;
- Π‘Π΅ΠΊΠΎΡ ΡΠ°Π·Π²ΠΈΠ²Π°Ρ ΠΈΠΌΠ° ΠΏΠΎΡΡΠ΅Π±Π° ΠΎΠ΄ ΡΠ°Π·Π»ΠΈΡΠ΅Π½ ΡΠ΅Ρ Π½Π° ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠΈ.
ΠΠΌΠ° ΠΈ Π΄ΡΡΠ³ΠΈ ΠΏΡΠΎΠ±Π»Π΅ΠΌΠΈ, Π½ΠΎ Π΄Π° Π²ΠΈ ΠΊΠ°ΠΆΠ°ΠΌ Π·Π° ΡΠ΅ΡΠ΅Π½ΠΈΠ΅ΡΠΎ.
ΠΠ΅Π½ΠΊΠΈΠ½Ρ Π²ΠΎ ΠΠΎΠΊΠ΅Ρ
ΠΠΈΠ΄Π΅ΡΡΠΈ Docker ΡΠ΅Π³Π° Π΅ Π΄ΠΎΠ±ΡΠΎ Π²ΠΎΡΠΏΠΎΡΡΠ°Π²Π΅Π½ Π²ΠΎ ΡΠ²Π΅ΡΠΎΡ Π½Π° ΡΠ°Π·Π²ΠΎΡΠΎΡ, ΡΠ΅ΡΠΈΡΠΈ ΡΓ¨ ΠΌΠΎΠΆΠ΅ Π΄Π° ΡΠ΅ ΡΠ°Π±ΠΎΡΠΈ ΡΠΎ ΠΏΠΎΠΌΠΎΡ Π½Π° Docker. ΠΠΎΠ΅ΡΠΎ ΡΠ΅ΡΠ΅Π½ΠΈΠ΅ Π΅ Π΄Π° Π³ΠΎ ΠΈΠΌΠ°ΠΌ ΠΠ΅Π½ΠΊΠΈΠ½Ρ Π²ΠΎ ΠΠΎΠΊΠ΅Ρ ΠΈ Π΄Π° ΠΌΠΎΠΆΠ°ΠΌ Π΄Π° ΡΠΏΡΠ°Π²ΡΠ²Π°ΠΌ ΡΠΎ Π΄ΡΡΠ³ΠΈ ΠΊΠΎΠ½ΡΠ΅ΡΠ½Π΅ΡΠΈ Π½Π° ΠΠΎΠΊΠ΅Ρ. ΠΠ²Π° ΠΏΡΠ°ΡΠ°ΡΠ΅ ΠΏΠΎΡΠ½Π° Π΄Π° ΡΠ΅ ΠΏΠΎΡΡΠ°Π²ΡΠ²Π° ΡΡΡΠ΅ Π²ΠΎ 2013 Π³ΠΎΠ΄ΠΈΠ½Π° Π²ΠΎ ΡΡΠ°ΡΠΈΡΠ°ΡΠ° β
ΠΠ°ΠΊΡΠ°ΡΠΊΠΎ, ΡΠ°ΠΌΠΎ ΡΡΠ΅Π±Π° Π΄Π° Π³ΠΎ ΠΈΠ½ΡΡΠ°Π»ΠΈΡΠ°ΡΠ΅ ΡΠ°ΠΌΠΈΠΎΡ Docker Π²ΠΎ ΡΠ°Π±ΠΎΡΠ΅Π½ ΠΊΠΎΠ½ΡΠ΅ΡΠ½Π΅Ρ ΠΈ Π΄Π° ΡΠ° ΠΌΠΎΠ½ΡΠΈΡΠ°ΡΠ΅ Π΄Π°ΡΠΎΡΠ΅ΠΊΠ°ΡΠ° /var/run/docker.sock
.
ΠΠ²Π΅ Π΅Π΄Π΅Π½ ΠΏΡΠΈΠΌΠ΅Ρ Dockerfile ΡΡΠΎ ΡΠ΅ ΠΏΠΎΠΊΠ°ΠΆΠ° Π·Π° ΠΠ΅Π½ΠΊΠΈΠ½Ρ.
FROM jenkins/jenkins:lts
USER root
RUN apt-get update &&
apt-get -y install apt-transport-https
ca-certificates
curl
gnupg2
git
software-properties-common &&
curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg > /tmp/dkey; apt-key add /tmp/dkey &&
add-apt-repository
"deb [arch=amd64] https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")
$(lsb_release -cs)
stable" &&
apt-get update &&
apt-get -y install docker-ce &&
usermod -aG docker jenkins
RUN curl -L https://github.com/docker/compose/releases/download/1.25.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose && chmod +x /usr/local/bin/docker-compose
RUN apt-get clean autoclean && apt-get autoremove βyes && rm -rf /var/lib/{apt,dpkg,cache,log}/
USER jenkins
Π’Π°ΠΊΠ°, Π΄ΠΎΠ±ΠΈΠ²ΠΌΠ΅ Docker ΠΊΠΎΠ½ΡΠ΅ΡΠ½Π΅Ρ ΠΊΠΎΡ ΠΌΠΎΠΆΠ΅ Π΄Π° Π³ΠΈ ΠΈΠ·Π²ΡΡΡΠ²Π° Docker ΠΊΠΎΠΌΠ°Π½Π΄ΠΈΡΠ΅ Π½Π° ΠΌΠ°ΡΠΈΠ½Π°ΡΠ° Π΄ΠΎΠΌΠ°ΡΠΈΠ½.
ΠΠ·Π³ΡΠ°Π΄Π±Π° Π½Π° ΠΏΠΎΡΡΠ°Π²ΡΠ²Π°ΡΠ΅
ΠΠ΅ΠΎΠ΄Π°ΠΌΠ½Π° ΠΠ΅Π½ΠΊΠΈΠ½Ρ Π΄ΠΎΠ±ΠΈ ΠΌΠΎΠΆΠ½ΠΎΡΡ Π΄Π° Π³ΠΈ ΠΎΠΏΠΈΡΠ΅ ΡΠ²ΠΎΠΈΡΠ΅ ΠΏΡΠ°Π²ΠΈΠ»Π° ΠΊΠΎΡΠΈΡΡΠ΅ΡΡΠΈ
ΠΠ½Π°ΡΠΈ, Π΄Π° ΡΡΠ°Π²ΠΈΠΌΠ΅ ΡΠΏΠ΅ΡΠΈΡΠ°Π»Π΅Π½ Dockerfile Π²ΠΎ ΡΠ°ΠΌΠΎΡΠΎ ΡΠΊΠ»Π°Π΄ΠΈΡΡΠ΅, ΠΊΠΎΠ΅ ΡΠ΅ Π³ΠΈ ΡΠΎΠ΄ΡΠΆΠΈ ΡΠΈΡΠ΅ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈ Π½Π΅ΠΎΠΏΡ ΠΎΠ΄Π½ΠΈ Π·Π° ΠΈΠ·Π³ΡΠ°Π΄Π±Π°ΡΠ°. ΠΠ° ΠΎΠ²ΠΎΡ Π½Π°ΡΠΈΠ½, ΡΠ°ΠΌΠΈΠΎΡ ΡΠ°Π·Π²ΠΈΠ²Π°Ρ ΠΌΠΎΠΆΠ΅ Π΄Π° ΠΏΠΎΠ΄Π³ΠΎΡΠ²ΠΈ ΠΏΠΎΠ²ΡΠΎΡΠ»ΠΈΠ²Π° ΡΡΠ΅Π΄ΠΈΠ½Π° ΠΈ Π½Π΅ΠΌΠ° Π΄Π° ΠΌΠΎΡΠ° Π΄Π° Π±Π°ΡΠ° ΠΎΠ΄ OPS Π΄Π° ΠΈΠ½ΡΡΠ°Π»ΠΈΡΠ° ΠΎΠ΄ΡΠ΅Π΄Π΅Π½Π° Π²Π΅ΡΠ·ΠΈΡΠ° Π½Π° Node.JS Π½Π° Π΄ΠΎΠΌΠ°ΡΠΈΠ½ΠΎΡ.
FROM node:12.10.0-alpine
RUN npm install yarn -g
ΠΠ²Π°Π° Π³ΡΠ°Π΄Π±Π° ΡΠ»ΠΈΠΊΠ° Π΅ ΠΏΠΎΠ³ΠΎΠ΄Π½Π° Π·Π° ΠΏΠΎΠ²Π΅ΡΠ΅ΡΠΎ Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΠΈ Node.JS. Π¨ΡΠΎ Π°ΠΊΠΎ, Π½Π° ΠΏΡΠΈΠΌΠ΅Ρ, Π²ΠΈ ΡΡΠ΅Π±Π° ΡΠ»ΠΈΠΊΠ° Π·Π° ΠΏΡΠΎΠ΅ΠΊΡ Π½Π° JVM ΡΠΎ Π²ΠΊΠ»ΡΡΠ΅Π½ ΡΠΊΠ΅Π½Π΅Ρ Π½Π° Π‘ΠΎΠ½Π°Ρ? Π‘Π»ΠΎΠ±ΠΎΠ΄Π½ΠΎ ΠΌΠΎΠΆΠ΅ΡΠ΅ Π΄Π° Π³ΠΈ ΠΈΠ·Π±Π΅ΡΠ΅ΡΠ΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠΈΡΠ΅ ΡΡΠΎ Π²ΠΈ ΡΠ΅ ΠΏΠΎΡΡΠ΅Π±Π½ΠΈ Π·Π° ΡΠΊΠ»ΠΎΠΏΡΠ²Π°ΡΠ΅.
FROM adoptopenjdk/openjdk12:latest
RUN apt update
&& apt install -y
bash unzip wget
RUN mkdir -p /usr/local/sonarscanner
&& cd /usr/local/sonarscanner
&& wget https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-3.3.0.1492-linux.zip
&& unzip sonar-scanner-cli-3.3.0.1492-linux.zip
&& mv sonar-scanner-3.3.0.1492-linux/* ./
&& rm sonar-scanner-cli-3.3.0.1492-linux.zip
&& rm -rf sonar-scanner-3.3.0.1492-linux
&& ln -s /usr/local/sonarscanner/bin/sonar-scanner /usr/local/bin/sonar-scanner
ENV PATH $PATH:/usr/local/sonarscanner/bin/
ENV SONAR_RUNNER_HOME /usr/local/sonarscanner/bin/
ΠΠ° ΠΎΠΏΠΈΡΠ°Π²ΠΌΠ΅ ΠΎΠΊΠΎΠ»ΠΈΠ½Π°ΡΠ° Π·Π° ΡΠΊΠ»ΠΎΠΏΡΠ²Π°ΡΠ΅, Π½ΠΎ ΠΊΠ°ΠΊΠ²Π° Π²ΡΡΠΊΠ° ΠΈΠΌΠ° ΠΠ΅Π½ΠΊΠΈΠ½Ρ ΡΠΎ ΡΠΎΠ°? Π Π°Π³Π΅Π½ΡΠΈΡΠ΅ Π½Π° ΠΠ΅Π½ΠΊΠΈΠ½Ρ ΠΌΠΎΠΆΠ°Ρ Π΄Π° ΡΠ°Π±ΠΎΡΠ°Ρ ΡΠΎ ΡΠ°ΠΊΠ²ΠΈ ΡΠ»ΠΈΠΊΠΈ Π½Π° ΠΠΎΠΊΠ΅Ρ ΠΈ Π΄Π° Π³ΠΈ Π³ΡΠ°Π΄Π°Ρ Π²Π½Π°ΡΡΠ΅ΡΠ½ΠΎ.
stage("Build project") {
agent {
docker {
image "project-build:${DOCKER_IMAGE_BRANCH}"
args "-v ${PWD}:/usr/src/app -w /usr/src/app"
reuseNode true
label "build-image"
}
}
steps {
sh "yarn"
sh "yarn build"
}
}
ΠΠΈΡΠ΅ΠΊΡΠΈΠ²Π° agent
ΠΊΠΎΡΠΈΡΡΠΈ ΠΈΠΌΠΎΡ docker
ΠΊΠ°Π΄Π΅ ΡΡΠΎ ΠΌΠΎΠΆΠ΅ΡΠ΅ Π΄Π° Π½Π°Π²Π΅Π΄Π΅ΡΠ΅:
- ΠΈΠΌΠ΅ΡΠΎ Π½Π° ΠΊΠΎΠ½ΡΠ΅ΡΠ½Π΅ΡΠΎΡ Π·Π° ΡΠΊΠ»ΠΎΠΏΡΠ²Π°ΡΠ΅ ΡΠΏΠΎΡΠ΅Π΄ Π²Π°ΡΠ°ΡΠ° ΠΏΠΎΠ»ΠΈΡΠΈΠΊΠ° Π·Π° ΠΈΠΌΠ΅Π½ΡΠ²Π°ΡΠ΅;
- Π°ΡΠ³ΡΠΌΠ΅Π½ΡΠΈ ΠΏΠΎΡΡΠ΅Π±Π½ΠΈ Π·Π° ΠΈΠ·Π²ΡΡΡΠ²Π°ΡΠ΅ Π½Π° ΠΊΠΎΠ½ΡΠ΅ΡΠ½Π΅ΡΠΎΡ Π·Π° ΠΈΠ·Π³ΡΠ°Π΄Π±Π°, ΠΊΠ°Π΄Π΅ ΡΡΠΎ Π²ΠΎ Π½Π°ΡΠΈΠΎΡ ΡΠ»ΡΡΠ°Ρ Π³ΠΎ ΠΌΠΎΠ½ΡΠΈΡΠ°ΠΌΠ΅ ΡΠ΅ΠΊΠΎΠ²Π½ΠΈΠΎΡ Π΄ΠΈΡΠ΅ΠΊΡΠΎΡΠΈΡΠΌ ΠΊΠ°ΠΊΠΎ Π΄ΠΈΡΠ΅ΠΊΡΠΎΡΠΈΡΠΌ Π²Π½Π°ΡΡΠ΅ Π²ΠΎ ΠΊΠΎΠ½ΡΠ΅ΡΠ½Π΅ΡΠΎΡ.
Π Π²Π΅ΡΠ΅ Π²ΠΎ ΡΠ΅ΠΊΠΎΡΠΈΡΠ΅ Π·Π° Π³ΡΠ°Π΄Π΅ΡΠ΅ ΡΠΊΠ°ΠΆΡΠ²Π°ΠΌΠ΅ ΠΊΠΎΠΈ ΠΊΠΎΠΌΠ°Π½Π΄ΠΈ Π΄Π° ΡΠ΅ ΠΈΠ·Π²ΡΡΠ°Ρ Π²Π½Π°ΡΡΠ΅ Π²ΠΎ Π°Π³Π΅Π½ΡΠΎΡ Π·Π° ΠΈΠ·Π³ΡΠ°Π΄Π±Π° Π½Π° Docker. ΠΠ²Π° ΠΌΠΎΠΆΠ΅ Π΄Π° Π±ΠΈΠ΄Π΅ ΡΓ¨, ΠΏΠ° Π·Π°ΡΠΎΠ° ΡΡΠ°ΡΡΡΠ²Π°ΠΌ ΠΈ ΡΠ°ΡΠΏΠΎΡΠ΅Π΄ΡΠ²Π°ΡΠ΅ Π½Π° Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΠΈ ΠΊΠΎΡΠΈΡΡΠ΅ΡΡΠΈ ansible.
ΠΠΎΠ΄ΠΎΠ»Ρ ΡΠ°ΠΊΠ°ΠΌ Π΄Π° ΠΏΡΠΈΠΊΠ°ΠΆΠ°ΠΌ Π³Π΅Π½Π΅ΡΠΈΡΠΊΠΈ Jenkinsfile ΡΡΠΎ ΠΌΠΎΠΆΠ΅ Π΄Π° Π³ΠΎ ΠΈΠ·Π³ΡΠ°Π΄ΠΈ Π΅Π΄Π½ΠΎΡΡΠ°Π²Π½Π° Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡΠ° Node.JS.
def DOCKER_IMAGE_BRANCH = ""
def GIT_COMMIT_HASH = ""
pipeline {
options {
buildDiscarder(
logRotator(
artifactDaysToKeepStr: "",
artifactNumToKeepStr: "",
daysToKeepStr: "",
numToKeepStr: "10"
)
)
disableConcurrentBuilds()
}
agent any
stages {
stage("Prepare build image") {
steps {
sh "docker build -f Dockerfile.build . -t project-build:${DOCKER_IMAGE_BRANCH}"
}
}
stage("Build project") {
agent {
docker {
image "project-build:${DOCKER_IMAGE_BRANCH}"
args "-v ${PWD}:/usr/src/app -w /usr/src/app"
reuseNode true
label "build-image"
}
}
steps {
sh "yarn"
sh "yarn build"
}
}
post {
always {
step([$class: "WsCleanup"])
cleanWs()
}
}
}
Π¨ΡΠΎ ΡΠ΅ ΡΠ»ΡΡΠΈ?
ΠΠ»Π°Π³ΠΎΠ΄Π°ΡΠ΅Π½ΠΈΠ΅ Π½Π° ΠΎΠ²ΠΎΡ ΠΌΠ΅ΡΠΎΠ΄, Π³ΠΈ ΡΠ΅ΡΠΈΠ²ΠΌΠ΅ ΡΠ»Π΅Π΄Π½ΠΈΠ²Π΅ ΠΏΡΠΎΠ±Π»Π΅ΠΌΠΈ:
- Π²ΡΠ΅ΠΌΠ΅ΡΠΎ Π·Π° ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΡΠ° Π½Π° ΡΠΊΠ»ΠΎΠΏΡΠ²Π°ΡΠ΅ Π½Π° ΠΎΠΊΠΎΠ»ΠΈΠ½Π°ΡΠ° Π΅ Π½Π°ΠΌΠ°Π»Π΅Π½ΠΎ Π½Π° 10 - 15 ΠΌΠΈΠ½ΡΡΠΈ ΠΏΠΎ ΠΏΡΠΎΠ΅ΠΊΡ;
- ΡΠ΅Π»ΠΎΡΠ½ΠΎ ΠΏΠΎΠ²ΡΠΎΡΠ»ΠΈΠ²Π° ΠΎΠΊΠΎΠ»ΠΈΠ½Π° Π·Π° Π³ΡΠ°Π΄Π΅ΡΠ΅ Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΠΈ, Π±ΠΈΠ΄Π΅ΡΡΠΈ ΠΌΠΎΠΆΠ΅ΡΠ΅ Π΄Π° ΡΠ° ΠΈΠ·Π³ΡΠ°Π΄ΠΈΡΠ΅ Π½Π° ΠΎΠ²ΠΎΡ Π½Π°ΡΠΈΠ½ Π½Π° Π²Π°ΡΠΈΠΎΡ Π»ΠΎΠΊΠ°Π»Π΅Π½ ΠΊΠΎΠΌΠΏΡΡΡΠ΅Ρ;
- Π½Π΅ΠΌΠ° ΠΏΡΠΎΠ±Π»Π΅ΠΌΠΈ ΡΠΎ ΠΊΠΎΠ½ΡΠ»ΠΈΠΊΡΠΈ ΠΏΠΎΠΌΠ΅ΡΡ ΡΠ°Π·Π»ΠΈΡΠ½ΠΈ Π²Π΅ΡΠ·ΠΈΠΈ Π½Π° Π°Π»Π°ΡΠΊΠΈ Π·Π° ΡΠΊΠ»ΠΎΠΏΡΠ²Π°ΡΠ΅;
- ΡΠ΅ΠΊΠΎΠ³Π°Ρ ΡΠΈΡΡ ΡΠ°Π±ΠΎΡΠ΅Π½ ΠΏΡΠΎΡΡΠΎΡ ΠΊΠΎΡ Π½Π΅ ΡΠ΅ Π·Π°ΡΠ½ΡΠ²Π°.
Π‘Π°ΠΌΠΎΡΠΎ ΡΠ΅ΡΠ΅Π½ΠΈΠ΅ Π΅ Π΅Π΄Π½ΠΎΡΡΠ°Π²Π½ΠΎ ΠΈ ΠΎΡΠΈΠ³Π»Π΅Π΄Π½ΠΎ ΠΈ Π²ΠΈ ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡΠ²Π° Π΄Π° Π΄ΠΎΠ±ΠΈΠ΅ΡΠ΅ Π½Π΅ΠΊΠΎΠΈ ΠΏΡΠ΅Π΄Π½ΠΎΡΡΠΈ. ΠΠ°, ΠΏΡΠ°Π³ΠΎΡ Π·Π° Π²Π»Π΅Π· ΠΌΠ°Π»ΠΊΡ ΡΠ΅ Π·Π³ΠΎΠ»Π΅ΠΌΠΈ Π²ΠΎ ΡΠΏΠΎΡΠ΅Π΄Π±Π° ΡΠΎ Π΅Π΄Π½ΠΎΡΡΠ°Π²Π½ΠΈΡΠ΅ ΠΊΠΎΠΌΠ°Π½Π΄ΠΈ Π·Π° ΡΠΊΠ»ΠΎΠΏΠΎΠ²ΠΈ, Π½ΠΎ ΡΠ΅Π³Π° ΠΏΠΎΡΡΠΎΠΈ Π³Π°ΡΠ°Π½ΡΠΈΡΠ° Π΄Π΅ΠΊΠ° ΡΠ΅ΠΊΠΎΠ³Π°Ρ ΡΠ΅ ΡΠ΅ Π³ΡΠ°Π΄ΠΈ ΠΈ ΡΠ°ΠΌΠΈΠΎΡ ΡΠ°Π·Π²ΠΈΠ²Π°Ρ ΠΌΠΎΠΆΠ΅ Π΄Π° ΠΈΠ·Π±Π΅ΡΠ΅ ΡΓ¨ ΡΡΠΎ Π΅ ΠΏΠΎΡΡΠ΅Π±Π½ΠΎ Π·Π° Π½Π΅Π³ΠΎΠ²ΠΈΠΎΡ ΠΏΡΠΎΡΠ΅Ρ Π½Π° Π³ΡΠ°Π΄Π΅ΡΠ΅.
ΠΠΎΠΆΠ΅ΡΠ΅ ΠΈΡΡΠΎ ΡΠ°ΠΊΠ° Π΄Π° ΡΠ° ΠΊΠΎΡΠΈΡΡΠΈΡΠ΅ ΡΠ»ΠΈΠΊΠ°ΡΠ° ΡΡΠΎ ΡΠ° ΡΠΎΠ±ΡΠ°Π²
ΠΡΠΈ ΠΏΠΈΡΡΠ²Π°ΡΠ΅ΡΠΎ Π½Π° ΠΎΠ²ΠΎΡ Π½Π°ΠΏΠΈΡ, ΡΠ΅ ΠΏΠΎΡΠ°Π²ΠΈ Π΄ΠΈΡΠΊΡΡΠΈΡΠ° Π·Π° ΠΊΠΎΡΠΈΡΡΠ΅ΡΠ΅ Π°Π³Π΅Π½ΡΠΈ Π½Π° ΠΎΠ΄Π΄Π°Π»Π΅ΡΠ΅Π½ΠΈ ΡΠ΅ΡΠ²Π΅ΡΠΈ Π·Π° Π΄Π° Π½Π΅ ΡΠ΅ Π²ΡΠΈΡΠ° Π³Π»Π°Π²Π½ΠΈΠΎΡ ΡΠ°Π·ΠΎΠ» ΠΊΠΎΡΠΈΡΡΠ΅ΡΡΠΈ ΠΏΡΠΈΠΊΠ»ΡΡΠΎΠΊ
ΠΠ·Π²ΠΎΡ: www.habr.com