เจ•เฉเจฌเจฐเจจเฉ‡เจŸเจธ เจ•เจฒเฉฑเจธเจŸเจฐ เจตเจฟเฉฑเจš เจ‡เฉฑเจ• เจชเฉเจฐเจพเจฃเฉ€ เจตเจฟเจธเจผเฉ‡เจธเจผเจคเจพ เจธเจผเจพเจ–เจพ เจจเฉ‚เฉฐ เจนเจŸเจพเจ‰เจฃเจพ

เจ•เฉเจฌเจฐเจจเฉ‡เจŸเจธ เจ•เจฒเฉฑเจธเจŸเจฐ เจตเจฟเฉฑเจš เจ‡เฉฑเจ• เจชเฉเจฐเจพเจฃเฉ€ เจตเจฟเจธเจผเฉ‡เจธเจผเจคเจพ เจธเจผเจพเจ–เจพ เจจเฉ‚เฉฐ เจนเจŸเจพเจ‰เจฃเจพ

เจนเฉˆเจฒเฉ‹! เจตเจฟเจธเจผเฉ‡เจธเจผเจคเจพ เจธเจผเจพเจ–เจพ (เจ‰เจฐเจซเจผ เจคเฉˆเจจเจพเจค เจชเฉเจฐเฉ€เจตเจฟเจŠ, เจฐเฉ€เจตเจฟเจŠ เจเจช) - เจ‡เจน เจ‰เจฆเฉ‹เจ‚ เจนเฉเฉฐเจฆเจพ เจนเฉˆ เจœเจฆเฉ‹เจ‚ เจจเจพ เจธเจฟเจฐเจซเจผ เจฎเจพเจธเจŸเจฐ เจฌเฉเจฐเจพเจ‚เจš เจจเฉ‚เฉฐ เจคเฉˆเจจเจพเจค เจ•เฉ€เจคเจพ เจœเจพเจ‚เจฆเจพ เจนเฉˆ, เจธเจ—เฉ‹เจ‚ เจนเจฐ เจ‡เฉฑเจ• เจตเจฟเจฒเฉฑเจ–เจฃ URL เจฒเจˆ เจชเฉเฉฑเจฒ เจฌเฉ‡เจจเจคเฉ€ เจตเฉ€ เจ•เฉ€เจคเฉ€ เจœเจพเจ‚เจฆเฉ€ เจนเฉˆเฅค เจคเฉเจธเฉ€เจ‚ เจœเจพเจ‚เจš เจ•เจฐ เจธเจ•เจฆเฉ‡ เจนเฉ‹ เจ•เจฟ เจ•เฉ€ เจ•เฉ‹เจก เจ‰เจคเจชเจพเจฆเจจ เจตเจพเจคเจพเจตเจฐเจฃ เจตเจฟเฉฑเจš เจ•เฉฐเจฎ เจ•เจฐเจฆเจพ เจนเฉˆ; เจตเจฟเจธเจผเฉ‡เจธเจผเจคเจพ เจฆเฉ‚เจœเฉ‡ เจชเฉเจฐเฉ‹เจ—เจฐเจพเจฎเจฐเจพเจ‚ เจœเจพเจ‚ เจ‰เจคเจชเจพเจฆ เจฎเจพเจนเจฐเจพเจ‚ เจจเฉ‚เฉฐ เจฆเจฟเจ–เจพเจˆ เจœเจพ เจธเจ•เจฆเฉ€ เจนเฉˆเฅค เจœเจฆเฉ‹เจ‚ เจคเฉเจธเฉ€เจ‚ เจ‡เฉฑเจ• เจชเฉเฉฑเจฒ เจฌเฉ‡เจจเจคเฉ€ เจตเจฟเฉฑเจš เจ•เฉฐเจฎ เจ•เจฐ เจฐเจนเฉ‡ เจนเฉ‹, เจคเจพเจ‚ เจชเฉเจฐเจพเจฃเฉ‡ เจ•เฉ‹เจก เจฒเจˆ เจนเจฐเฉ‡เจ• เจจเจตเฉ€เจ‚ เจ•เจฎเจฟเจŸ เจฎเฉŒเจœเฉ‚เจฆเจพ เจคเฉˆเจจเจพเจคเฉ€ เจจเฉ‚เฉฐ เจฎเจฟเจŸเจพ เจฆเจฟเฉฑเจคเจพ เจœเจพเจ‚เจฆเจพ เจนเฉˆ, เจ…เจคเฉ‡ เจจเจตเฉ‡เจ‚ เจ•เฉ‹เจก เจฒเจˆ เจจเจตเฉ€เจ‚ เจคเฉˆเจจเจพเจคเฉ€ เจฐเฉ‹เจฒ เจ†เจŠเจŸ เจนเฉ‹ เจœเจพเจ‚เจฆเฉ€ เจนเฉˆเฅค เจœเจฆเฉ‹เจ‚ เจคเฉเจธเฉ€เจ‚ เจฎเจพเจธเจŸเจฐ เจฌเฉเจฐเจพเจ‚เจš เจตเจฟเฉฑเจš เจชเฉเฉฑเจฒ เจฌเฉ‡เจจเจคเฉ€ เจจเฉ‚เฉฐ เจฎเจฟเจฒเจพเจ‰เจ‚เจฆเฉ‡ เจนเฉ‹ เจคเจพเจ‚ เจธเจตเจพเจฒ เจชเฉˆเจฆเจพ เจนเฉ‹ เจธเจ•เจฆเฉ‡ เจนเจจเฅค เจคเฉเจนเจพเจจเฉ‚เฉฐ เจนเฉเจฃ เจตเจฟเจธเจผเฉ‡เจธเจผเจคเจพ เจธเจผเจพเจ–เจพ เจฆเฉ€ เจฒเฉ‹เฉœ เจจเจนเฉ€เจ‚ เจนเฉˆ, เจชเจฐ เจ•เฉเจฌเจฐเจจเฉ‡เจŸเจธ เจธเจฐเฉ‹เจค เจ…เจœเฉ‡ เจตเฉ€ เจ•เจฒเฉฑเจธเจŸเจฐ เจตเจฟเฉฑเจš เจนเจจเฅค

เจตเจฟเจธเจผเฉ‡เจธเจผเจคเจพ เจธเจผเจพเจ–เจพเจตเจพเจ‚ เจฌเจพเจฐเฉ‡ เจนเฉ‹เจฐ

เจ•เฉเจฌเจฐเจจเฉ‡เจŸเจธ เจตเจฟเฉฑเจš เจตเจฟเจธเจผเฉ‡เจธเจผเจคเจพ เจธเจผเจพเจ–เจพเจตเจพเจ‚ เจฌเจฃเจพเจ‰เจฃ เจฆเจพ เจ‡เฉฑเจ• เจคเจฐเฉ€เจ•เจพ เจนเฉˆ เจจเจพเจฎ-เจธเจฅเจพเจจเจพเจ‚ เจฆเฉ€ เจตเจฐเจคเฉ‹เจ‚ เจ•เจฐเจจเจพเฅค เจธเฉฐเจ–เฉ‡เจช เจตเจฟเฉฑเจš, เจ‰เจคเจชเจพเจฆเจจ เจธเฉฐเจฐเจšเจจเจพ เจ‡เจธ เจคเจฐเฉเจนเจพเจ‚ เจฆเจฟเจ–เจพเจˆ เจฆเจฟเฉฐเจฆเฉ€ เจนเฉˆ:

kind: Namespace
apiVersion: v1
metadata:
  name: habr-back-end
...

kind: Deployment
apiVersion: apps/v1
metadata:
  namespace: habr-back-end
spec:
  replicas: 3
...

เจ‡เฉฑเจ• เจตเจฟเจธเจผเฉ‡เจธเจผเจคเจพ เจธเจผเจพเจ–เจพ เจฒเจˆ, เจ‡เฉฑเจ• เจจเฉ‡เจฎเจธเจชเฉ‡เจธ เจ‡เจธเจฆเฉ‡ เจชเจ›เจพเจฃเจ•เจฐเจคเจพ (เจ‰เจฆเจพเจนเจฐเจจ เจฒเจˆ, เจชเฉเฉฑเจฒ เจฌเฉ‡เจจเจคเฉ€ เจจเฉฐเจฌเจฐ) เจ…เจคเฉ‡ เจ•เจฟเจธเฉ‡ เจ•เจฟเจธเจฎ เจฆเจพ เจ…เจ—เฉ‡เจคเจฐ/เจชเฉ‹เจธเจŸเจซเจฟเจ•เจธ (เจ‰เจฆเจพเจนเจฐเจจ เจฒเจˆ, -เจชเฉ€เจ†เจฐ-):

kind: Namespace
apiVersion: v1
metadata:
  name: habr-back-end-pr-17
...

kind: Deployment
apiVersion: apps/v1
metadata:
  namespace: habr-back-end-pr-17
spec:
  replicas: 1
...

เจ†เจฎ เจคเฉŒเจฐ 'เจคเฉ‡, เจฎเฉˆเจ‚ เจฒเจฟเจ–เจฟเจ† เจ•เฉเจฌเจฐเจจเฉ‡เจŸเจธ เจ†เจชเจฐเฉ‡เจŸเจฐ (เจ‡เฉฑเจ• เจเจชเจฒเฉ€เจ•เฉ‡เจธเจผเจจ เจœเจฟเจธเจฆเฉ€ เจ•เจฒเฉฑเจธเจŸเจฐ เจธเจฐเฉ‹เจคเจพเจ‚ เจคเฉฑเจ• เจชเจนเฉเฉฐเจš เจนเฉˆ), Github 'เจคเฉ‡ เจชเฉเจฐเฉ‹เจœเฉˆเจ•เจŸ เจจเจพเจฒ เจฒเจฟเฉฐเจ• เจ•เจฐเฉ‹. เจ‡เจน เจ‰เจนเจจเจพเจ‚ เจจเจพเจฎ-เจธเจฅเจพเจจเจพเจ‚ เจจเฉ‚เฉฐ เจนเจŸเจพเจ‰เจ‚เจฆเจพ เจนเฉˆ เจœเฉ‹ เจชเฉเจฐเจพเจฃเฉ€ เจตเจฟเจธเจผเฉ‡เจธเจผเจคเจพ เจธเจผเจพเจ–เจพเจตเจพเจ‚ เจจเจพเจฒ เจธเจฌเฉฐเจงเจค เจนเจจเฅค เจ•เฉเจฌเจฐเจจเฉ‡เจŸเจธ เจตเจฟเฉฑเจš, เจœเฉ‡เจ•เจฐ เจคเฉเจธเฉ€เจ‚ เจ‡เฉฑเจ• เจจเฉ‡เจฎเจธเจชเฉ‡เจธ เจจเฉ‚เฉฐ เจฎเจฟเจŸเจพเจ‰เจ‚เจฆเฉ‡ เจนเฉ‹, เจคเจพเจ‚ เจ‰เจธ เจจเฉ‡เจฎเจธเจชเฉ‡เจธ เจตเจฟเฉฑเจš เจนเฉ‹เจฐ เจธเจฐเฉ‹เจค เจตเฉ€ เจ†เจชเจฃเฉ‡ เจ†เจช เจฎเจฟเจŸเจพ เจฆเจฟเฉฑเจคเฉ‡ เจœเจพเจ‚เจฆเฉ‡ เจนเจจเฅค

$ kubectl get pods --all-namespaces | grep -e "-pr-"
NAMESPACE            ... AGE
habr-back-end-pr-264 ... 4d8h
habr-back-end-pr-265 ... 5d7h

เจคเฉเจธเฉ€เจ‚ เจ‡เจธ เจฌเจพเจฐเฉ‡ เจชเฉœเฉเจน เจธเจ•เจฆเฉ‡ เจนเฉ‹ เจ•เจฟ เจตเจฟเจธเจผเฉ‡เจธเจผเจคเจพ เจธเจผเจพเจ–เจพเจตเจพเจ‚ เจจเฉ‚เฉฐ เจ‡เฉฑเจ• เจ•เจฒเฉฑเจธเจŸเจฐ เจตเจฟเฉฑเจš เจ•เจฟเจตเฉ‡เจ‚ เจฒเจพเจ—เฉ‚ เจ•เจฐเจจเจพ เจนเฉˆ เจ‡เฉฑเจฅเฉ‡ ะธ เจ‡เฉฑเจฅเฉ‡.

เจชเฉเจฐเฉ‡เจฐเจฃเจพ

เจšเจฒเฉ‹ เจจเจฟเจฐเฉฐเจคเจฐ เจเจ•เฉ€เจ•เจฐเจฃ (continuous integration):

  1. เจ…เจธเฉ€เจ‚ เจฌเฉเจฐเจพเจ‚เจš เจฒเจˆ เจ‡เฉฑเจ• เจจเจตเฉ€เจ‚ เจตเจšเจจเจฌเฉฑเจงเจคเจพ เจจเฉ‚เฉฐ เจงเฉฑเจ•เจฆเฉ‡ เจนเจพเจ‚.
  2. เจฌเจฟเจฒเจก 'เจคเฉ‡, เจฒเจฟเฉฐเจŸเจฐ เจ…เจคเฉ‡/เจœเจพเจ‚ เจŸเฉˆเจธเจŸ เจšเจฒเจพเจ เจœเจพเจ‚เจฆเฉ‡ เจนเจจเฅค
  3. เจ•เฉเจฌเจฐเจจเฉ‡เจŸเจธ เจชเฉเฉฑเจฒ เจฌเฉ‡เจจเจคเฉ€ เจธเฉฐเจฐเจšเจจเจพ เจซเจฒเจพเจˆ 'เจคเฉ‡ เจคเจฟเจ†เจฐ เจ•เฉ€เจคเฉ€ เจœเจพเจ‚เจฆเฉ€ เจนเฉˆ (เจ‰เจฆเจพเจนเจฐเจฃ เจฒเจˆ, เจ‡เจธเจฆเจพ เจจเฉฐเจฌเจฐ เจคเจฟเจ†เจฐ เจŸเฉˆเจฎเจชเจฒเฉ‡เจŸ เจตเจฟเฉฑเจš เจชเจพเจ‡เจ† เจœเจพเจ‚เจฆเจพ เจนเฉˆ)เฅค
  4. kubectl apply เจฆเฉ€ เจตเจฐเจคเฉ‹เจ‚ เจ•เจฐเจฆเฉ‡ เจนเฉ‹เจ, เจธเฉฐเจฐเจšเจจเจพ เจจเฉ‚เฉฐ เจ•เจฒเฉฑเจธเจŸเจฐ (เจกเจฟเจชเจฒเจพเจ‡) เจตเจฟเฉฑเจš เจœเฉ‹เฉœเจฟเจ† เจœเจพเจ‚เจฆเจพ เจนเฉˆเฅค
  5. เจชเฉเฉฑเจฒ เจฌเฉ‡เจจเจคเฉ€ เจจเฉ‚เฉฐ เจฎเจพเจธเจŸเจฐ เจฌเฉเจฐเจพเจ‚เจš เจตเจฟเฉฑเจš เจฎเจฟเจฒเจพเจ‡เจ† เจœเจพเจ‚เจฆเจพ เจนเฉˆเฅค

เจœเจฆเฉ‹เจ‚ เจคเฉเจธเฉ€เจ‚ เจ‡เฉฑเจ• เจชเฉเฉฑเจฒ เจฌเฉ‡เจจเจคเฉ€ เจตเจฟเฉฑเจš เจ•เฉฐเจฎ เจ•เจฐ เจฐเจนเฉ‡ เจนเฉ‹, เจคเจพเจ‚ เจชเฉเจฐเจพเจฃเฉ‡ เจ•เฉ‹เจก เจฒเจˆ เจนเจฐเฉ‡เจ• เจจเจตเฉ€เจ‚ เจ•เจฎเจฟเจŸ เจฎเฉŒเจœเฉ‚เจฆเจพ เจคเฉˆเจจเจพเจคเฉ€ เจจเฉ‚เฉฐ เจฎเจฟเจŸเจพ เจฆเจฟเฉฑเจคเจพ เจœเจพเจ‚เจฆเจพ เจนเฉˆ, เจ…เจคเฉ‡ เจจเจตเฉ‡เจ‚ เจ•เฉ‹เจก เจฒเจˆ เจจเจตเฉ€เจ‚ เจคเฉˆเจจเจพเจคเฉ€ เจฐเฉ‹เจฒ เจ†เจŠเจŸ เจนเฉ‹ เจœเจพเจ‚เจฆเฉ€ เจนเฉˆเฅค เจชเจฐ เจœเจฆเฉ‹เจ‚ เจ‡เฉฑเจ• เจชเฉเฉฑเจฒ เจฌเฉ‡เจจเจคเฉ€ เจจเฉ‚เฉฐ เจฎเจพเจธเจŸเจฐ เจฌเฉเจฐเจพเจ‚เจš เจตเจฟเฉฑเจš เจฎเจฟเจฒเจพเจ‡เจ† เจœเจพเจ‚เจฆเจพ เจนเฉˆ, เจคเจพเจ‚ เจธเจฟเจฐเจซเจผ เจฎเจพเจธเจŸเจฐ เจฌเฉเจฐเจพเจ‚เจš เจนเฉ€ เจฌเจฃเจพเจˆ เจœเจพเจตเฉ‡เจ—เฉ€เฅค เจจเจคเฉ€เจœเฉ‡ เจตเจœเฉ‹เจ‚, เจ‡เจน เจชเจคเจพ เจšเจฒเจฆเจพ เจนเฉˆ เจ•เจฟ เจ…เจธเฉ€เจ‚ เจชเจนเจฟเจฒเจพเจ‚ เจนเฉ€ เจชเฉเฉฑเจฒ เจฌเฉ‡เจจเจคเฉ€ เจฌเจพเจฐเฉ‡ เจญเฉเฉฑเจฒ เจ—เจ เจนเจพเจ‚, เจ…เจคเฉ‡ เจ‡เจธเจฆเฉ‡ เจ•เฉเจฌเจฐเจจเฉ‡เจŸเจธ เจธเจฐเฉ‹เจค เจ…เจœเฉ‡ เจตเฉ€ เจ•เจฒเฉฑเจธเจŸเจฐ เจตเจฟเฉฑเจš เจนเจจเฅค

เจ•เจฟเจตเฉ‡เจ‚ เจตเจฐเจคเจฃเจพ เจนเฉˆ

เจนเฉ‡เจ  เจฆเจฟเฉฑเจคเฉ€ เจ•เจฎเจพเจ‚เจก เจจเจพเจฒ เจชเฉเจฐเฉ‹เจœเฉˆเจ•เจŸ เจจเฉ‚เฉฐ เจธเจฅเจพเจชเจฟเจค เจ•เจฐเฉ‹:

$ kubectl apply -f https://raw.githubusercontent.com/dmytrostriletskyi/stale-feature-branch-operator/master/configs/production.yml

เจนเฉ‡เจ  เจฆเจฟเฉฑเจคเฉ€ เจธเจฎเฉฑเจ—เจฐเฉ€ เจฆเฉ‡ เจจเจพเจฒ เจ‡เฉฑเจ• เจซเจพเจˆเจฒ เจฌเจฃเจพเจ“ เจ…เจคเฉ‡ เจฆเฉเจ†เจฐเจพ เจธเจฅเจพเจชเจฟเจค เจ•เจฐเฉ‹ kubectl apply -f:

apiVersion: feature-branch.dmytrostriletskyi.com/v1
kind: StaleFeatureBranch
metadata:
  name: stale-feature-branch
spec:
  namespaceSubstring: -pr-
  afterDaysWithoutDeploy: 3

เจชเฉˆเจฐเจพเจฎเฉ€เจŸเจฐ เจจเฉ‡เจฎเจธเจชเฉ‡เจธ เจธเจฌเจธเจŸเฉเจฐเจฟเฉฐเจ— เจนเฉ‹เจฐ เจจเฉ‡เจฎเจธเจชเฉ‡เจธเจพเจ‚ เจคเฉ‹เจ‚ เจชเฉเฉฑเจฒ เจฌเฉ‡เจจเจคเฉ€เจ†เจ‚ เจฒเจˆ เจจเฉ‡เจฎเจธเจชเฉ‡เจธ เจซเจฟเจฒเจŸเจฐ เจ•เจฐเจจ เจฆเฉ€ เจฒเฉ‹เฉœ เจนเฉˆเฅค เจ‰เจฆเจพเจนเจฐเจจ เจฒเจˆ, เจœเฉ‡เจ•เจฐ เจ•เจฒเฉฑเจธเจŸเจฐ เจตเจฟเฉฑเจš เจนเฉ‡เจ เจพเจ‚ เจฆเจฟเฉฑเจคเฉ‡ เจจเจพเจฎ-เจธเจฅเจพเจจเจพเจ‚ เจนเจจ: habr-back-end, habr-front-end, habr-back-end-pr-17, habr-back-end-pr-33, เจซเจฟเจฐ เจนเจŸเจพเจ‰เจฃ เจฒเจˆ เจ‰เจฎเฉ€เจฆเจตเจพเจฐ เจนเฉ‹เจฃเจ—เฉ‡ habr-back-end-pr-17, habr-back-end-pr-33.

เจชเฉˆเจฐเจพเจฎเฉ€เจŸเจฐ afterDaysWithoutDeploy เจชเฉเจฐเจพเจฃเฉ‡ เจจเฉ‡เจฎเจธเจชเฉ‡เจธ เจจเฉ‚เฉฐ เจฎเจฟเจŸเจพเจ‰เจฃ เจฆเฉ€ เจฒเฉ‹เฉœ เจนเฉˆเฅค เจ‰เจฆเจพเจนเจฐเจจ เจฒเจˆ, เจœเฉ‡เจ•เจฐ เจจเฉ‡เจฎเจธเจชเฉ‡เจธ เจฌเจฃเจพเจ‡เจ† เจ—เจฟเจ† เจนเฉˆ 3 ะดะฝั 1 ั‡ะฐั เจตเจพเจชเจธ, เจ…เจคเฉ‡ เจชเฉˆเจฐเจพเจฎเฉ€เจŸเจฐ เจฆเจฐเจธเจพเจ‰เจ‚เจฆเจพ เจนเฉˆ 3 ะดะฝั, เจ‡เจธ เจจเฉ‡เจฎเจธเจชเฉ‡เจธ เจจเฉ‚เฉฐ เจฎเจฟเจŸเจพ เจฆเจฟเฉฑเจคเจพ เจœเจพเจตเฉ‡เจ—เจพเฅค เจ‡เจน เจ‰เจฒเจŸ เจฆเจฟเจธเจผเจพ เจตเจฟเฉฑเจš เจตเฉ€ เจ•เฉฐเจฎ เจ•เจฐเจฆเจพ เจนเฉˆ เจœเฉ‡เจ•เจฐ เจจเฉ‡เจฎเจธเจชเฉ‡เจธ เจฌเจฃเจพเจ‡เจ† เจ—เจฟเจ† เจนเฉˆ 2 ะดะฝั 23 ั‡ะฐัะฐ เจตเจพเจชเจธ, เจ…เจคเฉ‡ เจชเฉˆเจฐเจพเจฎเฉ€เจŸเจฐ เจฆเจฐเจธเจพเจ‰เจ‚เจฆเจพ เจนเฉˆ 3 ะดะฝั, เจ‡เจธ เจจเฉ‡เจฎเจธเจชเฉ‡เจธ เจจเฉ‚เฉฐ เจฎเจฟเจŸเจพเจ‡เจ† เจจเจนเฉ€เจ‚ เจœเจพเจตเฉ‡เจ—เจพเฅค

เจ‡เฉฑเจ• เจนเฉ‹เจฐ เจชเฉˆเจฐเจพเจฎเฉ€เจŸเจฐ เจนเฉˆ, เจ‡เจน เจ‡เจธ เจฒเจˆ เจœเจผเจฟเฉฐเจฎเฉ‡เจตเจพเจฐ เจนเฉˆ เจ•เจฟ เจ•เจฟเฉฐเจจเฉ€ เจตเจพเจฐ เจธเจพเจฐเฉ‡ เจจเจพเจฎ-เจธเจฅเจพเจจเจพเจ‚ เจจเฉ‚เฉฐ เจธเจ•เฉˆเจจ เจ•เจฐเจจเจพ เจนเฉˆ เจ…เจคเฉ‡ เจฌเจฟเจจเจพเจ‚ เจคเฉˆเจจเจพเจคเฉ€ เจฆเฉ‡ เจฆเจฟเจจเจพเจ‚ เจฆเฉ€ เจœเจพเจ‚เจš เจ•เจฐเจจเฉ€ เจนเฉˆ - เจนเจฐ เจฎเจฟเฉฐเจŸ เจฆเฉ€ เจœเจพเจ‚เจš เจ•เจฐเฉ‹. เจฎเฉ‚เจฒ เจฐเฉ‚เจช เจตเจฟเฉฑเจš เจ‡เจน เจฌเจฐเจพเจฌเจฐ เจนเฉˆ 30 ะผะธะฝัƒั‚ะฐะผ.

เจ‡เจน เจ•เฉฐเจฎ เจ•เจฐเจฆเจพ เจนเฉˆ

เจ…เจญเจฟเจ†เจธ เจตเจฟเฉฑเจš, เจคเฉเจนเจพเจจเฉ‚เฉฐ เจฒเฉ‹เฉœ เจนเฉ‹เจตเฉ‡เจ—เฉ€:

  1. เจกเฉŒเจ•เจฐ เจ‡เฉฑเจ• เจ…เจฒเฉฑเจ—-เจฅเจฒเฉฑเจ— เจตเจพเจคเจพเจตเจฐเจฃ เจตเจฟเฉฑเจš เจ•เฉฐเจฎ เจ•เจฐเจจ เจฒเจˆเฅค
  2. เจฎเจฟเจจเฉ€เจ•เฉ‚เจฌเฉ‡ เจธเจฅเจพเจจเจ• เจคเฉŒเจฐ 'เจคเฉ‡ เจ•เฉเจฌเจฐเจจเฉ‡เจŸเจธ เจ•เจฒเฉฑเจธเจŸเจฐ เจจเฉ‚เฉฐ เจตเจงเจพเจเจ—เจพเฅค
  3. kubectl - เจ•เจฒเฉฑเจธเจŸเจฐ เจชเฉเจฐเจฌเฉฐเจงเจจ เจฒเจˆ เจ•เจฎเจพเจ‚เจก เจฒเจพเจˆเจจ เจ‡เฉฐเจŸเจฐเจซเฉ‡เจธเฅค

เจ…เจธเฉ€เจ‚ เจธเจฅเจพเจจเจ• เจคเฉŒเจฐ 'เจคเฉ‡ เจ•เฉเจฌเจฐเจจเฉ‡เจŸเจธ เจ•เจฒเฉฑเจธเจŸเจฐ เจจเฉ‚เฉฐ เจตเจงเจพเจ‰เจ‚เจฆเฉ‡ เจนเจพเจ‚:

$ minikube start --vm-driver=docker
minikube v1.11.0 on Darwin 10.15.5
Using the docker driver based on existing profile.
Starting control plane node minikube in cluster minikube.

เจธเฉฐเจ•เฉ‡เจค kubectl เจฎเฉ‚เจฒ เจฐเฉ‚เจช เจตเจฟเฉฑเจš เจธเจฅเจพเจจเจ• เจ•เจฒเฉฑเจธเจŸเจฐ เจฆเฉ€ เจตเจฐเจคเฉ‹เจ‚ เจ•เจฐเฉ‹:

$ kubectl config use-context minikube
Switched to context "minikube".

เจ‰เจคเจชเจพเจฆเจจ เจตเจพเจคเจพเจตเจฐเจฃ เจฒเจˆ เจธเฉฐเจฐเจšเจจเจพ เจกเจพเจŠเจจเจฒเฉ‹เจก เจ•เจฐเฉ‹:

$ curl https://raw.githubusercontent.com/dmytrostriletskyi/stale-feature-branch-operator/master/configs/production.yml > stale-feature-branch-production-configs.yml

เจ•เจฟเจ‰เจ‚เจ•เจฟ เจชเฉเจฐเฉ‹เจกเจ•เจธเจผเจจ เจ•เฉŒเจ‚เจซเจฟเจ—เจฐเฉ‡เจธเจผเจจเจพเจ‚ เจจเฉ‚เฉฐ เจชเฉเจฐเจพเจฃเฉ‡ เจจเจพเจฎ-เจธเจฅเจพเจจเจพเจ‚ เจฆเฉ€ เจœเจพเจ‚เจš เจ•เจฐเจจ เจฒเจˆ เจธเฉฐเจฐเจšเจฟเจค เจ•เฉ€เจคเจพ เจ—เจฟเจ† เจนเฉˆ, เจ…เจคเฉ‡ เจธเจพเจกเฉ‡ เจจเจตเฉ‡เจ‚ เจฌเจฃเฉ‡ เจ•เจฒเฉฑเจธเจŸเจฐ เจตเจฟเฉฑเจš เจ‰เจน เจจเจนเฉ€เจ‚ เจนเจจ, เจ…เจธเฉ€เจ‚ เจตเจพเจคเจพเจตเจฐเจฃ เจตเฉ‡เจฐเฉ€เจเจฌเจฒ เจจเฉ‚เฉฐ เจฌเจฆเจฒ เจฆเฉ‡เจตเจพเจ‚เจ—เฉ‡ IS_DEBUG 'เจคเฉ‡ true. เจ‡เจธ เจฎเฉเฉฑเจฒ เจฆเฉ‡ เจจเจพเจฒ เจชเฉˆเจฐเจพเจฎเฉ€เจŸเจฐ afterDaysWithoutDeploy เจจเฉ‚เฉฐ เจงเจฟเจ†เจจ เจตเจฟเฉฑเจš เจจเจนเฉ€เจ‚ เจฐเฉฑเจ–เจฟเจ† เจœเจพเจ‚เจฆเจพ เจนเฉˆ เจ…เจคเฉ‡ เจจเจพเจฎ-เจธเจฅเจพเจจเจพเจ‚ เจฆเฉ€ เจคเฉˆเจจเจพเจคเฉ€ เจ•เฉ€เจคเฉ‡ เจฌเจฟเจจเจพเจ‚ เจฆเจฟเจจเจพเจ‚ เจฒเจˆ เจœเจพเจ‚เจš เจจเจนเฉ€เจ‚ เจ•เฉ€เจคเฉ€ เจœเจพเจ‚เจฆเฉ€, เจธเจฟเจฐเจซเจผ เจธเจฌเจธเจŸเฉเจฐเจฟเฉฐเจ— เจฆเฉ€ เจฎเฉŒเจœเฉ‚เจฆเจ—เฉ€ เจฒเจˆ (-pr-).

เจœเฉ‡เจ•เจฐ เจคเฉเจธเฉ€เจ‚ 'เจคเฉ‡ เจนเฉ‹ Linux:

$ sed -i 's|false|true|g' stale-feature-branch-production-configs.yml

เจœเฉ‡เจ•เจฐ เจคเฉเจธเฉ€เจ‚ 'เจคเฉ‡ เจนเฉ‹ macOS:

$ sed -i "" 's|false|true|g' stale-feature-branch-production-configs.yml

เจชเฉเจฐเฉ‹เจœเฉˆเจ•เจŸ เจจเฉ‚เฉฐ เจธเจฅเจพเจชเจฟเจค เจ•เจฐเจจเจพ:

$ kubectl apply -f stale-feature-branch-production-configs.yml

เจœเจพเจ‚เจš เจ•เจฐ เจฐเจฟเจนเจพ เจนเฉˆ เจ•เจฟ เจ•เจฒเฉฑเจธเจŸเจฐ เจตเจฟเฉฑเจš เจ‡เฉฑเจ• เจธเจฐเฉ‹เจค เจชเฉเจฐเจ—เจŸ เจนเฉ‹เจ‡เจ† เจนเฉˆ StaleFeatureBranch:

$ kubectl api-resources | grep stalefeaturebranches
NAME                 ... APIGROUP                             ... KIND
stalefeaturebranches ... feature-branch.dmytrostriletskyi.com ... StaleFeatureBranch

เจ…เจธเฉ€เจ‚ เจœเจพเจ‚เจš เจ•เจฐเจฆเฉ‡ เจนเจพเจ‚ เจ•เจฟ เจ‡เฉฑเจ• เจ†เจชเจฐเฉ‡เจŸเจฐ เจ•เจฒเฉฑเจธเจŸเจฐ เจตเจฟเฉฑเจš เจชเฉเจฐเจ—เจŸ เจนเฉ‹เจ‡เจ† เจนเฉˆ:

$ kubectl get pods --namespace stale-feature-branch-operator
NAME                                           ... STATUS  ... AGE
stale-feature-branch-operator-6bfbfd4df8-m7sch ... Running ... 38s

เจœเฉ‡ เจคเฉเจธเฉ€เจ‚ เจ‡เจธเจฆเฉ‡ เจฒเฉŒเจ—เจธ เจจเฉ‚เฉฐ เจฆเฉ‡เจ–เจฆเฉ‡ เจนเฉ‹, เจคเจพเจ‚ เจ‡เจน เจธเจฐเฉ‹เจคเจพเจ‚ เจฆเฉ€ เจชเฉเจฐเจ•เจฟเจฐเจฟเจ† เจ•เจฐเจจ เจฒเจˆ เจคเจฟเจ†เจฐ เจนเฉˆ StaleFeatureBranch:

$ kubectl logs stale-feature-branch-operator-6bfbfd4df8-m7sch -n stale-feature-branch-operator
... "msg":"Operator Version: 0.0.1"}
...
... "msg":"Starting EventSource", ... , "source":"kind source: /, Kind="}
... "msg":"Starting Controller", ...}
... "msg":"Starting workers", ..., "worker count":1}

เจ…เจธเฉ€เจ‚ เจฐเฉˆเจกเฉ€เจฎเฉ‡เจก เจ‡เฉฐเจธเจŸเจพเจฒ เจ•เจฐเจฆเฉ‡ เจนเจพเจ‚ fixtures (เจ•เจฒเฉฑเจธเจŸเจฐ เจธเจฐเฉ‹เจคเจพเจ‚ เจฆเฉ‡ เจฎเจพเจกเจฒเจฟเฉฐเจ— เจฒเจˆ เจคเจฟเจ†เจฐ-เจ•เฉ€เจคเฉ€ เจธเฉฐเจฐเจšเจจเจพ) เจ‡เฉฑเจ• เจธเจฐเฉ‹เจค เจฒเจˆ StaleFeatureBranch:

$ kubectl apply -f https://raw.githubusercontent.com/dmytrostriletskyi/stale-feature-branch-operator/master/fixtures/stale-feature-branch.yml

เจธเฉฐเจฐเจšเจจเจพ เจธเจฌเจธเจŸเจฐเจฟเฉฐเจ— เจจเจพเจฒ เจจเฉ‡เจฎเจธเจชเฉ‡เจธ เจ–เฉ‹เจœเจฃ เจฒเจˆ เจฆเจฐเจธเจพเจ‰เจ‚เจฆเฉ€ เจนเฉˆ -pr- เจ‡เฉฑเจ• เจตเจพเจฐ เจ…เฉฐเจฆเจฐ 1 ะผะธะฝัƒั‚ัƒ.:

apiVersion: feature-branch.dmytrostriletskyi.com/v1
kind: StaleFeatureBranch
metadata:
  name: stale-feature-branch
spec:
  namespaceSubstring: -pr-
  afterDaysWithoutDeploy: 1 
  checkEveryMinutes: 1

เจ†เจชเจฐเฉ‡เจŸเจฐ เจจเฉ‡ เจœเจตเจพเจฌ เจฆเจฟเฉฑเจคเจพ เจนเฉˆ เจ…เจคเฉ‡ เจจเจพเจฎ-เจธเจฅเจพเจจเจพเจ‚ เจฆเฉ€ เจœเจพเจ‚เจš เจ•เจฐเจจ เจฒเจˆ เจคเจฟเจ†เจฐ เจนเฉˆ:

$ kubectl logs stale-feature-branch-operator-6bfbfd4df8-m7sch -n stale-feature-branch-operator
... "msg":"Stale feature branch is being processing.","namespaceSubstring":"-pr-","afterDaysWithoutDeploy":1,"checkEveryMinutes":1,"isDebug":"true"}

เจธเจฅเจพเจชเจฟเจค เจ•เจฐเฉ‹ fixtures, เจœเจฟเจธ เจตเจฟเฉฑเจš เจฆเฉ‹ เจจเฉ‡เจฎ-เจธเจชเฉ‡เจธ (project-pr-1, project-pr-2) เจ…เจคเฉ‡ เจ‰เจน deployments, services, ingress, เจ‡เจคเจ†เจฆเจฟ:

$ kubectl apply -f https://raw.githubusercontent.com/dmytrostriletskyi/stale-feature-branch-operator/master/fixtures/first-feature-branch.yml -f https://raw.githubusercontent.com/dmytrostriletskyi/stale-feature-branch-operator/master/fixtures/second-feature-branch.yml
...
namespace/project-pr-1 created
deployment.apps/project-pr-1 created
service/project-pr-1 created
horizontalpodautoscaler.autoscaling/project-pr-1 created
secret/project-pr-1 created
configmap/project-pr-1 created
ingress.extensions/project-pr-1 created
namespace/project-pr-2 created
deployment.apps/project-pr-2 created
service/project-pr-2 created
horizontalpodautoscaler.autoscaling/project-pr-2 created
secret/project-pr-2 created
configmap/project-pr-2 created
ingress.extensions/project-pr-2 created

เจ…เจธเฉ€เจ‚ เจœเจพเจ‚เจš เจ•เจฐเจฆเฉ‡ เจนเจพเจ‚ เจ•เจฟ เจ‰เจชเจฐเฉ‹เจ•เจค เจธเจพเจฐเฉ‡ เจธเจฐเฉ‹เจค เจธเจซเจฒเจคเจพเจชเฉ‚เจฐเจตเจ• เจฌเจฃเจพเจ เจ—เจ เจนเจจ:

$ kubectl get namespace,pods,deployment,service,horizontalpodautoscaler,configmap,ingress -n project-pr-1 && kubectl get namespace,pods,deployment,service,horizontalpodautoscaler,configmap,ingress -n project-pr-2
...
NAME                              ... READY ... STATUS  ... AGE
pod/project-pr-1-848d5fdff6-rpmzw ... 1/1   ... Running ... 67s

NAME                         ... READY ... AVAILABLE ... AGE
deployment.apps/project-pr-1 ... 1/1   ... 1         ... 67s
...

เจ•เจฟเจ‰เจ‚เจ•เจฟ เจ…เจธเฉ€เจ‚ เจธเจผเจพเจฎเจฒ เจ•เฉ€เจคเจพ เจนเฉˆ debug, เจจเฉ‡เจฎเจธเจชเฉ‡เจธ project-pr-1 ะธ project-pr-2, เจ‡เจธเจฒเจˆ เจนเฉ‹เจฐ เจธเจพเจฐเฉ‡ เจธเจฐเฉ‹เจคเจพเจ‚ เจจเฉ‚เฉฐ เจชเฉˆเจฐเจพเจฎเฉ€เจŸเจฐ เจจเฉ‚เฉฐ เจงเจฟเจ†เจจ เจตเจฟเฉฑเจš เจฒเจ เจฌเจฟเจจเจพเจ‚ เจคเฉเจฐเฉฐเจค เจฎเจฟเจŸเจพเจ‰เจฃเจพ เจนเฉ‹เจตเฉ‡เจ—เจพ afterDaysWithoutDeploy. เจ‡เจธเจจเฉ‚เฉฐ เจ†เจชเจฐเฉ‡เจŸเจฐ เจฒเฉŒเจ—เจธ เจตเจฟเฉฑเจš เจฆเฉ‡เจ–เจฟเจ† เจœเจพ เจธเจ•เจฆเจพ เจนเฉˆ:

$ kubectl logs stale-feature-branch-operator-6bfbfd4df8-m7sch -n stale-feature-branch-operator
... "msg":"Namespace should be deleted due to debug mode is enabled.","namespaceName":"project-pr-1"}
... "msg":"Namespace is being processing.","namespaceName":"project-pr-1","namespaceCreationTimestamp":"2020-06-16 18:43:58 +0300 EEST"}
... "msg":"Namespace has been deleted.","namespaceName":"project-pr-1"}
... "msg":"Namespace should be deleted due to debug mode is enabled.","namespaceName":"project-pr-2"}
... "msg":"Namespace is being processing.","namespaceName":"project-pr-2","namespaceCreationTimestamp":"2020-06-16 18:43:58 +0300 EEST"}
... "msg":"Namespace has been deleted.","namespaceName":"project-pr-2"}

เจœเฉ‡เจ•เจฐ เจคเฉเจธเฉ€เจ‚ เจธเจฐเฉ‹เจคเจพเจ‚ เจฆเฉ€ เจ‰เจชเจฒเจฌเจงเจคเจพ เจฆเฉ€ เจœเจพเจ‚เจš เจ•เจฐเจฆเฉ‡ เจนเฉ‹, เจคเจพเจ‚ เจ‰เจน เจธเจฅเจฟเจคเฉ€ เจตเจฟเฉฑเจš เจนเฉ‹เจฃเจ—เฉ‡ Terminating (เจฎเจฟเจŸเจพเจ‰เจฃ เจฆเฉ€ เจชเฉเจฐเจ•เจฟเจฐเจฟเจ†) เจœเจพเจ‚ เจชเจนเจฟเจฒเจพเจ‚ เจนเฉ€ เจฎเจฟเจŸเจพเจ‡เจ† เจ—เจฟเจ† (เจ•เจฎเจพเจ‚เจก เจ†เจ‰เจŸเจชเฉเฉฑเจŸ เจ–เจพเจฒเฉ€ เจนเฉˆ)เฅค

$ kubectl get namespace,pods,deployment,service,horizontalpodautoscaler,configmap,ingress -n project-pr-1 && kubectl get namespace,pods,deployment,service,horizontalpodautoscaler,configmap,ingress -n project-pr-2
...

เจคเฉเจธเฉ€เจ‚ เจฐเจšเจจเจพ เจชเฉเจฐเจ•เจฟเจฐเจฟเจ† เจจเฉ‚เฉฐ เจฆเฉเจนเจฐเจพ เจธเจ•เจฆเฉ‡ เจนเฉ‹ fixtures เจ•เจˆ เจตเจพเจฐ เจ…เจคเฉ‡ เจฏเจ•เฉ€เจจเฉ€ เจฌเจฃเจพเจ“ เจ•เจฟ เจ‰เจน เจ‡เฉฑเจ• เจฎเจฟเฉฐเจŸ เจฆเฉ‡ เจ…เฉฐเจฆเจฐ เจนเจŸเจพ เจฆเจฟเฉฑเจคเฉ‡ เจ—เจ เจนเจจเฅค

เจฌเจฆเจฒ

เจ•เจฒเฉฑเจธเจŸเจฐ เจตเจฟเฉฑเจš เจ•เฉฐเจฎ เจ•เจฐเจจ เจตเจพเจฒเฉ‡ เจ†เจชเจฐเฉ‡เจŸเจฐ เจฆเฉ€ เจฌเจœเจพเจ เจ•เฉ€ เจ•เฉ€เจคเจพ เจœเจพ เจธเจ•เจฆเจพ เจนเฉˆ? เจ‡เฉฑเจฅเฉ‡ เจฌเจนเฉเจค เจธเจพเจฐเฉ‡ เจคเจฐเฉ€เจ•เฉ‡ เจนเจจ, เจ‰เจน เจธเจพเจฐเฉ‡ เจ…เจชเฉ‚เจฐเจฃ เจนเจจ (เจ…เจคเฉ‡ เจ‰เจนเจจเจพเจ‚ เจฆเฉ€เจ†เจ‚ เจ•เจฎเฉ€เจ†เจ‚ เจตเจฟเจ…เจ•เจคเฉ€เจ—เจค เจนเจจ), เจ…เจคเฉ‡ เจนเจฐ เจ•เฉ‹เจˆ เจ†เจชเจฃเฉ‡ เจฒเจˆ เจซเฉˆเจธเจฒเจพ เจ•เจฐเจฆเจพ เจนเฉˆ เจ•เจฟ เจ•เจฟเจธเฉ‡ เจ–เจพเจธ เจชเฉเจฐเฉ‹เจœเฉˆเจ•เจŸ เจฒเจˆ เจธเจญ เจคเฉ‹เจ‚ เจตเจงเฉ€เจ† เจ•เฉ€ เจนเฉˆ:

  1. เจฎเจพเจธเจŸเจฐ เจฌเฉเจฐเจพเจ‚เจš เจฆเฉ‡ เจจเจฟเจฐเฉฐเจคเจฐ เจเจ•เฉ€เจ•เจฐเจฃ เจฆเฉ‡ เจฆเฉŒเจฐเจพเจจ เจตเจฟเจธเจผเฉ‡เจธเจผเจคเจพ เจธเจผเจพเจ–เจพ เจจเฉ‚เฉฐ เจฎเจฟเจŸเจพเจ“เฅค

    • เจ…เจœเจฟเจนเจพ เจ•เจฐเจจ เจฒเจˆ, เจคเฉเจนเจพเจจเฉ‚เฉฐ เจ‡เจน เจœเจพเจฃเจจ เจฆเฉ€ เจœเจผเจฐเฉ‚เจฐเจค เจนเฉˆ เจ•เจฟ เจ•เจฟเจนเฉœเฉ€ เจชเฉเฉฑเจฒ เจฌเฉ‡เจจเจคเฉ€ เจ‰เจธ เจชเฉเจฐเจคเฉ€เจฌเฉฑเจงเจคเจพ เจจเจพเจฒ เจธเจฌเฉฐเจงเจค เจนเฉˆ เจœเฉ‹ เจฌเจฃเจพเจˆ เจœเจพ เจฐเจนเฉ€ เจนเฉˆเฅค เจ•เจฟเจ‰เจ‚เจ•เจฟ เจตเจฟเจธเจผเฉ‡เจธเจผเจคเจพ เจธเจผเจพเจ–เจพ เจจเฉ‡เจฎเจธเจชเฉ‡เจธ เจตเจฟเฉฑเจš เจชเฉเฉฑเจฒ เจฌเฉ‡เจจเจคเฉ€ เจชเจ›เจพเจฃเจ•เจฐเจคเจพ เจธเจผเจพเจฎเจฒ เจนเฉเฉฐเจฆเจพ เจนเฉˆ - เจ‡เจธเจฆเจพ เจจเฉฐเจฌเจฐ, เจœเจพเจ‚ เจธเจผเจพเจ–เจพ เจฆเจพ เจจเจพเจฎ, เจชเจ›เจพเจฃเจ•เจฐเจคเจพ เจจเฉ‚เฉฐ เจนเจฎเฉ‡เจธเจผเจพ เจ•เจฎเจฟเจŸ เจตเจฟเฉฑเจš เจจเจฟเจฐเจงเจพเจฐเจค เจ•เจฐเจจเจพ เจนเฉ‹เจตเฉ‡เจ—เจพเฅค
    • เจฎเจพเจธเจŸเจฐ เจฌเฉเจฐเจพเจ‚เจš เจฌเจฟเจฒเจก เจซเฉ‡เจฒ เจนเฉ‹ เจฐเจนเฉ‡ เจนเจจเฅค เจ‰เจฆเจพเจนเจฐเจจ เจฒเจˆ, เจคเฉเจนเจพเจกเฉ‡ เจ•เฉ‹เจฒ เจนเฉ‡เจ เจพเจ‚ เจฆเจฟเฉฑเจคเฉ‡ เจชเฉœเจพเจ… เจนเจจ: เจชเฉเจฐเฉ‹เจœเฉˆเจ•เจŸ เจจเฉ‚เฉฐ เจกเจพเจŠเจจเจฒเฉ‹เจก เจ•เจฐเฉ‹, เจŸเฉˆเจธเจŸ เจšเจฒเจพเจ“, เจชเฉเจฐเฉ‹เจœเฉˆเจ•เจŸ เจฌเจฃเจพเจ“, เจฐเฉ€เจฒเฉ€เจœเจผ เจ•เจฐเฉ‹, เจธเฉ‚เจšเจจเจพเจตเจพเจ‚ เจญเฉ‡เจœเฉ‹, เจ†เจ–เจฐเฉ€ เจชเฉเฉฑเจฒ เจฌเฉ‡เจจเจคเฉ€ เจฆเฉ€ เจตเจฟเจธเจผเฉ‡เจธเจผเจคเจพ เจธเจผเจพเจ–เจพ เจจเฉ‚เฉฐ เจธเจพเจซเจผ เจ•เจฐเฉ‹เฅค เจœเฉ‡เจ•เจฐ เจจเฉ‹เจŸเฉ€เจซเจฟเจ•เฉ‡เจธเจผเจจ เจญเฉ‡เจœเจฃ เจตเฉ‡เจฒเฉ‡ เจฌเจฟเจฒเจก เจซเฉ‡เจฒ เจนเฉ‹ เจœเจพเจ‚เจฆเจพ เจนเฉˆ, เจคเจพเจ‚ เจคเฉเจนเจพเจจเฉ‚เฉฐ เจ•เจฒเฉฑเจธเจŸเจฐ เจฆเฉ‡ เจธเจพเจฐเฉ‡ เจธเจฐเฉ‹เจคเจพเจ‚ เจจเฉ‚เฉฐ เจนเฉฑเจฅเฉ€เจ‚ เจฎเจฟเจŸเจพเจ‰เจฃเจพ เจนเฉ‹เจตเฉ‡เจ—เจพเฅค
    • เจธเจนเฉ€ เจธเฉฐเจฆเจฐเจญ เจคเฉ‹เจ‚ เจฌเจฟเจจเจพเจ‚, เจฎเจพเจธเจŸเจฐ เจฌเจฟเจฒเจก เจตเจฟเฉฑเจš เจตเจฟเจธเจผเฉ‡เจธเจผเจคเจพ เจธเจผเจพเจ–เจพเจตเจพเจ‚ เจจเฉ‚เฉฐ เจฎเจฟเจŸเจพเจ‰เจฃเจพ เจธเจชเฉฑเจธเจผเจŸ เจจเจนเฉ€เจ‚ เจนเฉˆเฅค

  2. เจตเฉˆเจฌเจนเฉเฉฑเจ• เจฆเฉ€ เจตเจฐเจคเฉ‹เจ‚ เจ•เจฐเจจเจพ (เจ‰เจฆเจพเจนเจฐเจจ).

    • เจ‡เจน เจคเฉเจนเจพเจกเฉ€ เจชเจนเฉเฉฐเจš เจจเจนเฉ€เจ‚ เจนเฉ‹ เจธเจ•เจฆเฉ€เฅค เจ‰เจฆเจพเจนเจฐเจจ เจฒเจˆ, เจตเจฟเฉฑเจš เจœเฉ‡เจจเจ•เจฟเฉฐเจธ, เจ•เฉ‡เจตเจฒ เจ‡เฉฑเจ• เจ•เจฟเจธเจฎ เจฆเฉ€ เจชเจพเจˆเจชเจฒเจพเจˆเจจ เจธเจฐเฉ‹เจค เจ•เฉ‹เจก เจตเจฟเฉฑเจš เจ‡เจธเจฆเฉ€เจ†เจ‚ เจธเฉฐเจฐเจšเจจเจพเจตเจพเจ‚ เจจเฉ‚เฉฐ เจธเฉเจฐเฉฑเจ–เจฟเจ…เจค เจ•เจฐเจจ เจฆเฉ€ เจธเจฎเจฐเฉฑเจฅเจพ เจฆเจพ เจธเจฎเจฐเจฅเจจ เจ•เจฐเจฆเฉ€ เจนเฉˆเฅค เจตเฉˆเจฌเจนเฉเฉฑเจ•เจธ เจฆเฉ€ เจตเจฐเจคเฉ‹เจ‚ เจ•เจฐเจฆเฉ‡ เจธเจฎเฉ‡เจ‚, เจคเฉเจนเจพเจจเฉ‚เฉฐ เจ‰เจนเจจเจพเจ‚ 'เจคเฉ‡ เจชเฉเจฐเจ•เจฟเจฐเจฟเจ† เจ•เจฐเจจ เจฒเจˆ เจ†เจชเจฃเฉ€ เจ–เฉเจฆ เจฆเฉ€ เจธเจ•เฉเจฐเจฟเจชเจŸ เจฒเจฟเจ–เจฃ เจฆเฉ€ เจฒเฉ‹เฉœ เจนเฉเฉฐเจฆเฉ€ เจนเฉˆเฅค เจ‡เจธ เจธเจ•เฉเจฐเจฟเจชเจŸ เจจเฉ‚เฉฐ เจœเฉ‡เจจเจ•เจฟเฉฐเจธ เจ‡เฉฐเจŸเจฐเจซเฉ‡เจธ เจตเจฟเฉฑเจš เจฐเฉฑเจ–เจฃเจพ เจนเฉ‹เจตเฉ‡เจ—เจพ, เจœเจฟเจธ เจจเฉ‚เฉฐ เจ•เจพเจ‡เจฎ เจฐเฉฑเจ–เจฃเจพ เจฎเฉเจธเจผเจ•เจฒ เจนเฉˆเฅค

  3. เจฒเจฟเจ–เฉ‹ เจ•เฉเจฐเฉ‹เจจเจœเฉŒเจฌ เจ…เจคเฉ‡ เจ•เฉเจฌเจฐเจจเฉ‡เจŸเจธ เจ•เจฒเฉฑเจธเจŸเจฐ เจธเจผเจพเจฎเจฒ เจ•เจฐเฉ‹เฅค

    • เจฒเจฟเจ–เจฃ เจ…เจคเฉ‡ เจธเจนเจพเจ‡เจคเจพ 'เจคเฉ‡ เจธเจฎเจพเจ‚ เจฌเจฟเจคเจพเจ‰เจฃเจพ.
    • เจ“เจชเจฐเฉ‡เจŸเจฐ เจชเจนเจฟเจฒเจพเจ‚ เจนเฉ€ เจ‡เฉฑเจ• เจธเจฎเจพเจจ เจธเจผเฉˆเจฒเฉ€ เจตเจฟเฉฑเจš เจ•เฉฐเจฎ เจ•เจฐเจฆเจพ เจนเฉˆ, เจฆเจธเจคเจพเจตเฉ‡เจœเจผเฉ€ เจ…เจคเฉ‡ เจธเจฎเจฐเจฅเจฟเจค เจนเฉˆเฅค

เจฒเฉ‡เจ– เจตเฉฑเจฒ เจคเฉเจนเจพเจกเจพ เจงเจฟเจ†เจจ เจฆเฉ‡เจฃ เจฒเจˆ เจคเฉเจนเจพเจกเจพ เจงเฉฐเจจเจตเจพเจฆเฅค Github 'เจคเฉ‡ เจชเฉเจฐเฉ‹เจœเฉˆเจ•เจŸ เจจเจพเจฒ เจฒเจฟเฉฐเจ• เจ•เจฐเฉ‹.

เจธเจฐเฉ‹เจค: www.habr.com

เจ‡เฉฑเจ• เจŸเจฟเฉฑเจชเจฃเฉ€ เจœเฉ‹เฉœเฉ‹