ოპტიმიზაცია

ისწავლეთ Docker-ის image-ების, კონტეინერების და Docker-ის საერთო წარმადობის ოპტიმიზაცია

Docker-ის ოპტიმიზაცია

Docker-ის ოპტიმიზაცია მოიცავს image-ის ზომის, build-ის დროის, runtime წარმადობისა და რესურსების გამოყენების გაუმჯობესებას. ეს ოპტიმიზაციები იწვევს უფრო სწრაფ deployment-ებს, შემცირებულ ხარჯებსა და აპლიკაციის უკეთეს წარმადობას. კარგად ოპტიმიზირებული Docker გარემო უზრუნველყოფს რესურსების ეფექტურ გამოყენებას, უფრო სწრაფ CI/CD მილსადენებს, აპლიკაციის გაშვების გაუმჯობესებულ დროსა და გაძლიერებულ უსაფრთხოების მდგომარეობას.

Docker-ის ოპტიმიზაციას შეიძლება მივუდგეთ რამდენიმე კუთხით:

  • Image-ის ოპტიმიზაცია: ზომის შემცირება და build-ის ეფექტურობის გაუმჯობესება
  • Build-ის წარმადობა: image-ის შექმნის პროცესის დაჩქარება
  • Runtime-ის ოპტიმიზაცია: კონტეინერის შესრულების ეფექტურობის გაძლიერება
  • რესურსების მართვა: CPU-ს, მეხსიერებისა და I/O-ს გამოყენების კონტროლი
  • ინფრასტრუქტურის ოპტიმიზაცია: Docker daemon-ისა და ჰოსტი სისტემის რეგულირება

Image-ის ოპტიმიზაცია

მრავალეტაპიანი Build-ები

გამოიყენეთ მრავალეტაპიანი build-ები უფრო მცირე production image-ების შესაქმნელად, build-დროის დამოკიდებულებების runtime მოთხოვნებისგან გამოყოფით:

# Build ეტაპი - მოიცავს ყველა build დამოკიდებულებასა და ინსტრუმენტს
FROM node:16 AS builder
WORKDIR /app
# დააკოპირეთ დამოკიდებულებები პირველ რიგში ფენების ქეშირების გამოსაყენებლად
COPY package*.json ./
RUN npm install
# დააკოპირეთ აპლიკაციის კოდი
COPY . .
# აპლიკაციის build
RUN npm run build

# Production ეტაპი - ბევრად მცირე საბაზისო image-ი მხოლოდ runtime მოთხოვნებით
FROM nginx:alpine
# დააკოპირეთ მხოლოდ build არტეფაქტები builder ეტაპიდან
COPY --from=builder /app/build /usr/share/nginx/html
# არასავალდებულო: დააკოპირეთ მხოლოდ runtime-ისთვის საჭირო კონკრეტული ფაილები
COPY --from=builder /app/config/nginx.conf /etc/nginx/conf.d/default.conf
# დააყენეთ არა-root მომხმარებელი უკეთესი უსაფრთხოებისთვის
USER nginx

მრავალეტაპიან build-ებს რამდენიმე უპირატესობა აქვს:

  • დრამატულად მცირე საბოლოო image-ები (ხშირად 10-20-ჯერ ზომის შემცირება)
  • build-დროისა და runtime დამოკიდებულებების გამოყოფა
  • შემცირებული თავდასხმის ზედაპირი ნაკლები დაინსტალირებული პაკეტებით
  • უკეთესი ფენების ქეშირება უფრო სწრაფი ხელახალი build-ებისთვის
  • უფრო უსაფრთხო image-ები build ინსტრუმენტებისა და საწყისი კოდის გარეშე

ფენების მინიმიზაცია

Docker image-ები შედგება ფენებისგან და თითოეული ფენა ამატებს ზედნადებს. ოპტიმიზაცია მოახდინეთ არასაჭირო ფენების შემცირებით:

  • გააერთიანეთ დაკავშირებული ბრძანებები ერთ RUN ინსტრუქციაში
  • გამოიყენეთ && ბრძანებების ლოგიკურად დასაკავშირებლად
  • გაასუფთავეთ დროებითი ფაილები და პაკეტების ქეშები იმავე ფენაში
  • დააჯგუფეთ ინსტალაციები სტაბილურობის/ცვლილების სიხშირის მიხედვით
# ცუდი მაგალითი - თითოეული ბრძანება ქმნის ახალ ფენას
# RUN apt-get update
# RUN apt-get install -y package1
# RUN apt-get install -y package2
# RUN apt-get clean

# კარგი მაგალითი - ერთი ფენა სათანადო გასუფთავებით
RUN apt-get update && \
    apt-get install -y \
      package1 \
      package2 \
      --no-install-recommends && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/* && \
    # აპლიკაცია-სპეციფიური გასუფთავება
    rm -rf /tmp/* /var/tmp/* && \
    # დარწმუნდით, რომ ყველა პაკეტის ინსტალაცია წარმატებით დასრულდა
    package1 --version && package2 --version

ყოველი ფენა:

  • ამატებს მეტამონაცემების ზედნადებს (ჩვეულებრივ ~4KB თითო ფენაზე)
  • გავლენას ახდენს build-ისა და pull-ის დროზე
  • გავლენას ახდენს ფენების ქეშის ეფექტურობაზე
  • ხელს უწყობს image-ის ზომის საერთო სირთულეს

მიუხედავად იმისა, რომ Docker-ს აქვს 127 ფენის მკაცრი ლიმიტი, კარგი წესია, რომ production image-ში 20-ზე ნაკლები ფენა გქონდეთ.

გამოიყენეთ .dockerignore

შექმენით .dockerignore ფაილი არასაჭირო ფაილების build კონტექსტიდან გამოსარიცხად. ეს ამცირებს build-ის დროს, კონტექსტის ზომას და ხელს უშლის მგრძნობიარე ინფორმაციის image-ებში მოხვედრას:

# ვერსიების კონტროლი
.git
.gitignore
.svn
.hg

# Development არტეფაქტები
node_modules
bower_components
vendor
*.o
*.obj
*.exe
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib64/
parts/
sdist/
var/
.installed.cfg

# ლოგები და მონაცემთა ბაზები
*.log
logs/
*.sql
*.sqlite
*.sqlite3
*.db

# გარემო და საიდუმლოებები
.env
.env.*
.venv
.aws/
.ssh/
.config/
.npm/
.cache/
*.pem
*.key
*_rsa
*_dsa
*_ed25519
*_ecdsa
credentials.json

# IDE ფაილები
.idea/
.vscode/
*.swp
*.swo
.DS_Store
Thumbs.db

# ტესტირება
coverage/
.coverage
htmlcov/
.pytest_cache/
.tox/
.nox/

# Docker-სპეციფიური
Dockerfile*
docker-compose*
.dockerignore

კარგად კონფიგურირებული .dockerignore-ის უპირატესობები:

  • ამცირებს build კონტექსტის ზომას (შეუძლია build-ის დროის მნიშვნელოვნად გაუმჯობესება)
  • ხელს უშლის არასაჭირო ქეშის ინვალიდაციას
  • აუმჯობესებს უსაფრთხოებას საიდუმლოებებისა და რწმუნებათა სიგელების გამორიცხვით
  • ხდის build-ებს უფრო დეტერმინისტულს ცვლადი შინაარსის გამორიცხვით
  • ამცირებს გამტარუნარიანობის გამოყენებას build კონტექსტის დისტანციურ Docker daemon-ებზე გადაცემისას

ასევე შეგიძლიათ გამოიყენოთ ნიმუშების დამთხვევა .gitignore-ის მსგავსად:

  • **/temp* - ემთხვევა ნებისმიერ ფაილს ან დირექტორიას, რომელიც იწყება "temp"-ით
  • !important.log - უარყოფს წინა ნიმუშს, important.log-ის ჩათვლით
  • #comment - კომენტარები დოკუმენტაციისთვის

შეარჩიეთ შესაბამისი საბაზისო Image-ები

საბაზისო image-ის შერჩევა მნიშვნელოვნად მოქმედებს image-ის ზომაზე, უსაფრთხოებასა და წარმადობაზე:

  • გამოიყენეთ ოფიციალური slim ან alpine ვარიანტები
    • Alpine: უკიდურესად მცირე (~5MB), მაგრამ იყენებს musl libc-ს glibc-ის ნაცვლად
    • Slim ვარიანტები: შეკვეცილი ოფიციალური image-ები მინიმალური პაკეტებით (~40-60MB)
    • Debian/Ubuntu-ზე დაფუძნებული image-ები: უკეთესი თავსებადობა, მაგრამ უფრო დიდი ზომა
  • განიხილეთ distroless image-ები production-ისთვის
    • შეიცავს მხოლოდ თქვენს აპლიკაციას და მის runtime დამოკიდებულებებს
    • არ აქვს პაკეტების მენეჯერი, shell, ან სხვა უტილიტები
    • მინიმალური თავდასხმის ზედაპირი და მცირე ზომა
    • მაგალითები: gcr.io/distroless/java, gcr.io/distroless/nodejs
    • რთული დებაგინგისთვის, მაგრამ შესანიშნავია უსაფრთხოებისთვის
  • იყავით კონკრეტული image-ის თეგებთან
    • ყოველთვის გამოიყენეთ ვერსიის ცხადი თეგები (მაგ., node:16.14.2-alpine3.15)
    • მოერიდეთ latest თეგს განმეორებადი build-ებისთვის
    • განიხილეთ image-ის დაიჯესტების გამოყენება უცვლელობისთვის: node@sha256:3e36d7d8458e14...
    • დააბალანსეთ სიახლე და სტაბილურობა ვერსიების არჩევისას
  • აირჩიეთ აპლიკაციის მოთხოვნების მიხედვით
    • CPU არქიტექტურის თავსებადობა (x86_64, ARM64 და ა.შ.)
    • საჭირო სისტემური ბიბლიოთეკები და დამოკიდებულებები
    • უსაფრთხოების პატჩების განახლების სიხშირე
    • საზოგადოების მხარდაჭერა და დოკუმენტაცია

საბაზისო image-ის ზომის შედარება:

node:16                 # ~910MB
node:16-slim            # ~175MB
node:16-alpine          # ~110MB
gcr.io/distroless/nodejs:16  # ~80MB

განიხილეთ სტანდარტიზებული, უსაფრთხოების თვალსაზრისით გამკაცრებული საბაზისო image-ების შექმნა თქვენი ორგანიზაციისთვის, რომლებიც მოიცავს საერთო კონფიგურაციებს, მონიტორინგის აგენტებსა და უსაფრთხოების პატჩებს.

Build-ის წარმადობა

# ჩართეთ BuildKit (Docker 18.09+)
export DOCKER_BUILDKIT=1

# ან ჩართეთ მუდმივად daemon.json-ში
# { "features": { "buildkit": true } }

# Build BuildKit-ით და ვრცელი გამოსავლით
docker build --progress=plain -t my-app .

# გამოიყენეთ build ქეში კონკრეტული image-ებიდან (ეხმარება CI/CD-ში)
docker build --cache-from my-app:previous -t my-app:latest .

# BuildKit-ის გაფართოებული ფუნქციები
# საიდუმლოს მიმაგრება build-ის დროს (არ იქნება საბოლოო image-ში)
docker build --secret id=npmrc,src=.npmrc -t my-app .

# SSH აგენტის მიმაგრება კერძო რეპოზიტორიაზე წვდომისთვის
docker build --ssh default -t my-app .

# build ქეშის ექსპორტი registry-ში განაწილებული ქეშირებისთვის
docker build --push -t my-app:latest \
  --cache-to type=registry,ref=my-registry.io/cache/my-app:buildcache \
  --cache-from type=registry,ref=my-registry.io/cache/my-app:buildcache .

# inline ქეშის მეტამონაცემების გამოყენება registry ქეშირებისთვის
docker build --push \
  --build-arg BUILDKIT_INLINE_CACHE=1 \
  -t my-app:latest .

# დამოუკიდებელი ეტაპების პარალელიზაცია
# (BuildKit ავტომატურად ახდენს დამოუკიდებელი ეტაპების პარალელიზაციას)
docker build -t my-app --target production .

Dockerfile-ში გამოიყენეთ BuildKit-სპეციფიური ფუნქციები სინტაქსის დირექტივით:

# syntax=docker/dockerfile:1.4
FROM node:16-alpine AS builder
# საიდუმლოს მიმაგრება ფენაში გამოჩენის გარეშე
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm install
# SSH აგენტის მიმაგრება კერძო რეპოზე წვდომისთვის
RUN --mount=type=ssh mkdir -p ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts
# ქეშის მიმაგრება პაკეტების მენეჯერისთვის
RUN --mount=type=cache,target=/root/.npm npm install

კონტეინერის Runtime ოპტიმიზაცია

Runtime ოპტიმიზაცია უზრუნველყოფს, რომ კონტეინერები მუშაობენ ეფექტურად, საიმედოდ და უსაფრთხოდ deployment-ისას. ეს ოპტიმიზაციები გავლენას ახდენს რესურსების გამოყენებაზე, გაშვების დროზე, სტაბილურობასა და უსაფრთხოების მდგომარეობაზე.

რესურსების შეზღუდვები

შესაბამისი რესურსების ლიმიტების დაყენება ხელს უშლის კონტეინერებს გადაჭარბებული რესურსების მოხმარებაში ან მეზობელ კონტეინერებზე ზემოქმედებაში:

# CPU-სა და მეხსიერების შეზღუდვა
docker run -d --name app \
  # შეზღუდვა 1.5 CPU ბირთვამდე (CPU წილები)
  --cpus=1.5 \
  # მყარი მეხსიერების ლიმიტი (კონტეინერი ითიშება გადაჭარბებისას)
  --memory=512m \
  # რბილი მეხსიერების რეზერვაცია (კონტეინერი ცდილობს დარჩეს ქვემოთ)
  --memory-reservation=256m \
  # მეხსიერების swappiness (0-100, დაბალი = ნაკლები swap)
  --memory-swappiness=0 \
  # CPU დაგეგმვის პრიორიტეტი
  --cpu-shares=1024 \
  # შეზღუდვა კონკრეტულ CPU ბირთვებზე
  --cpuset-cpus="0,1" \
  # PID-ების შეზღუდვა (ხელს უშლის fork bomb-ებს)
  --pids-limit=100 \
  # Block I/O წონები
  --blkio-weight=500 \
  # ulimit-ების დაყენება
  --ulimit nofile=8192:16384 \
  # OOM ქულის კორექტირება (-1000-დან 1000-მდე, დაბალი = ნაკლებად სავარაუდოა, რომ გაითიშოს)
  --oom-score-adj=500 \
  my-app:latest

ამ შეზღუდვებს რამდენიმე უპირატესობა აქვს:

  • პროგნოზირებადი წარმადობა რესურსების იზოლაციის გზით
  • დაცვა "ხმაურიანი მეზობლის" პრობლემებისგან
  • გაუმჯობესებული ჰოსტის სტაბილურობა რესურსების გამოფიტვის თავიდან აცილებით
  • უფრო ზუსტი სიმძლავრის დაგეგმვა და დაგეგმვა
  • უკეთესი მომსახურების ხარისხის (QoS) მართვა

რესურსების შეზღუდვები უნდა იყოს მორგებული თითოეული აპლიკაციის საჭიროებებზე და დაფუძნებული წარმადობის პროფაილირებაზე და არა თვითნებურ მნიშვნელობებზე.

მხოლოდ წაკითხვადი ფაილური სისტემა

მხოლოდ წაკითხვადი ფაილური სისტემების გამოყენება მნიშვნელოვან უსაფრთხოების უპირატესობებს იძლევა, კონტეინერის შინაარსის runtime-ში მოდიფიკაციის თავიდან აცილებით:

# root ფაილური სისტემის მხოლოდ წაკითხვადად მიმაგრება
docker run -d --name app \
  # მთელი ფაილური სისტემის მხოლოდ წაკითხვადად ქცევა
  --read-only \
  # კონკრეტული დირექტორიების ჩაწერადად დაშვება tmpfs-ის გამოყენებით (მეხსიერებაში)
  --tmpfs /tmp:rw,size=256m,mode=1777 \
  --tmpfs /var/run:rw,size=64m \
  --tmpfs /var/cache:rw,size=128m \
  # მიმაგრებული volume-ის გამოყენება მონაცემებისთვის, რომლებსაც მდგრადობა სჭირდება
  -v app-data:/data:rw \
  # კონკრეტული ჰოსტის დირექტორიების მხოლოდ წაკითხვადად მიმაგრება
  -v /etc/config:/etc/app-config:ro \
  # უსაფრთხოების ოფციების დაყენება
  --security-opt="no-new-privileges:true" \
  my-app:latest

ეს მიდგომა:

  • ხელს უშლის აპლიკაციის ბინარების runtime მოდიფიკაციას
  • ამსუბუქებს გარკვეული ტიპის შეტევების გავლენას
  • აიძულებს მუდმივი მონაცემების სათანადო ექსტერნალიზაციას
  • ხდის კონტეინერებს უფრო უცვლელსა და პროგნოზირებადს
  • ეხმარება აპლიკაციის ვარაუდების იდენტიფიცირებაში ფაილურ სისტემაზე წვდომის შესახებ

აპლიკაციებს შეიძლება დასჭირდეთ ადაპტაცია მხოლოდ წაკითხვად ფაილურ სისტემებთან სამუშაოდ, განსაკუთრებით მათ, რომლებიც ცდილობენ ჩაწერონ თავიანთ ინსტალაციის დირექტორიებში ან ელიან დროებითი ფაილების შექმნას არასტანდარტულ ადგილებში.

სათანადო გაჩერების სიგნალი

შესაბამისი გაჩერების სიგნალების კონფიგურაცია უზრუნველყოფს კონტეინერის კორექტულ შეწყვეტას, მონაცემთა კორუფციისა და სერვისის შეფერხების თავიდან აცილებით:

# გაჩერების სიგნალის განსაზღვრა Dockerfile-ში
STOPSIGNAL SIGTERM

# გაჩერების სიგნალის გადაფარვა runtime-ში
docker run -d --stop-signal SIGTERM my-app:latest

# გაჩერების тайმაუტის კონფიგურაცია (წამები SIGKILL-მდე)
docker run -d --stop-timeout=30 my-app:latest

კონტეინერის სასიცოცხლო ციკლის სიგნალების გაგება:

  1. SIGTERM (ნაგულისხმევი): ითხოვს კორექტულ შეწყვეტას, იძლევა გასუფთავების საშუალებას
  2. SIGKILL: დაუყოვნებლივი იძულებითი შეწყვეტა, გასუფთავება შეუძლებელია
  3. SIGINT: ტერმინალის შეწყვეტა (Ctrl+C-ს მსგავსად), შეიძლება განსხვავებულად დამუშავდეს
  4. SIGHUP: ტერმინალის გათიშვა, ზოგიერთი აპლიკაცია იყენებს კონფიგურაციის ხელახლა ჩატვირთვისთვის

სათანადო შეწყვეტის დამუშავება მოიცავს:

  • აპლიკაცია იჭერს და ამუშავებს SIGTERM-ს
  • ასრულებს მიმდინარე ტრანზაქციებს
  • სწორად ხურავს მონაცემთა ბაზის კავშირებს
  • ასრულებს დისკზე ჩაწერას და ასუფთავებს ბუფერებს
  • რეგისტრაციიდან იხსნება სერვისების აღმოჩენისას
  • აბრუნებს შესაბამის გასვლის კოდს

მორგებული აპლიკაციებისთვის, დანერგეთ სათანადო სიგნალების დამმუშავებლები:

// Node.js მაგალითი
process.on('SIGTERM', async () => {
  console.log('კორექტული გათიშვა დაიწყო');
  await closeConnections();
  await flushBuffers();
  console.log('კორექტული გათიშვა დასრულდა');
  process.exit(0);
});

Healthcheck-ები

Healthcheck-ები ეხმარება Docker-ს კონტეინერის ჯანმრთელობის მონიტორინგში და არაჯანსაღი კონტეინერების ავტომატურ გადატვირთვაში. ისინი განასხვავებენ გაშვებულ კონტეინერებსა და გამართულად მომუშავე აპლიკაციებს შორის:

# healthcheck-ის დამატება Dockerfile-ში
HEALTHCHECK --interval=30s --timeout=3s --start-period=60s --retries=3 \
  CMD curl -f http://localhost/health || exit 1
# healthcheck-ის განსაზღვრა runtime-ში
docker run -d --name app \
  --health-cmd="curl -f http://localhost:8080/actuator/health || exit 1" \
  --health-interval=30s \
  --health-timeout=5s \
  --health-retries=3 \
  --health-start-period=60s \
  my-app:latest

Healthcheck-ის პარამეტრების ახსნა:

  • interval: დრო შემოწმებებს შორის (ნაგულისხმევი: 30წმ)
  • timeout: მაქსიმალური დრო შემოწმების დასასრულებლად (ნაგულისხმევი: 30წმ)
  • start-period: საშეღავათო პერიოდი ინიციალიზაციისთვის (ნაგულისხმევი: 0წმ)
  • retries: ზედიზედ წარუმატებლობების რაოდენობა არაჯანსაღად ჩათვლამდე (ნაგულისხმევი: 3)

ეფექტური healthcheck ბრძანებები უნდა:

  • იყოს მსუბუქი და სწრაფად შესრულებადი
  • ამოწმებდეს კრიტიკულ აპლიკაციის ფუნქციონალობას
  • ჰქონდეს მინიმალური დამოკიდებულებები
  • აბრუნებდეს შესაბამის გასვლის კოდებს (0 = ჯანსაღი, 1 = არაჯანსაღი)
  • თავიდან აიცილოს ცრუ დადებითი/უარყოფითი შედეგები
  • მოიცავდეს გონივრულ тайმაუტებს

მაგალითები სხვადასხვა ტიპის აპლიკაციებისთვის:

# ვებ აპლიკაცია
HEALTHCHECK CMD curl -f http://localhost/ || exit 1

# მონაცემთა ბაზა
HEALTHCHECK CMD pg_isready -U postgres || exit 1

# API სერვისი
HEALTHCHECK CMD wget -O- http://localhost:8080/actuator/health | grep UP || exit 1

# Worker/ფონური სერვისი
HEALTHCHECK CMD pgrep -f worker.js || exit 1

Healthcheck-ები საშუალებას აძლევს ორკესტრაციის პლატფორმებს მიიღონ ინტელექტუალური დაგეგმვის გადაწყვეტილებები და უზრუნველყონ წარუმატებელი კონტეინერების ავტომატური გამოსწორება.

ქსელის წარმადობა

ქსელის წარმადობამ შეიძლება მნიშვნელოვნად იმოქმედოს კონტეინერებს შორის კომუნიკაციის შეყოვნებაზე, გამტარუნარიანობასა და აპლიკაციის საერთო წარმადობაზე. Docker გთავაზობთ რამდენიმე ქსელის ოპტიმიზაციის ოფციას:

# გამოიყენეთ host ქსელი უკეთესი წარმადობისთვის (როდესაც მიზანშეწონილია)
# აქრობს ქსელის თარგმნის ზედნადებს, მაგრამ ამცირებს იზოლაციას
docker run -d --network host my-app:latest

# კონტეინერის DNS-ის ოპტიმიზაცია ძებნის შეყოვნების თავიდან ასაცილებლად
docker run -d --dns 8.8.8.8 --dns 1.1.1.1 --dns-search example.com my-app:latest

# DNS ოფციების კონფიგურაცია daemon.json-ში ყველა კონტეინერისთვის
# {
#   "dns": ["8.8.8.8", "8.8.4.4"],
#   "dns-search": ["example.com"]
# }

# MTU-ს კონფიგურაცია უკეთესი ქსელის წარმადობისთვის
# სასარგებლოა VPN-ებთან, overlay ქსელებთან ან უჩვეულო ქსელის ტოპოლოგიებთან მუშაობისას
docker network create --opt com.docker.network.driver.mtu=1400 my-network

# გამოიყენეთ გამოყოფილი MAC მისამართი პროგნოზირებადი ქსელისთვის
docker run -d --mac-address="02:42:ac:11:00:02" my-app:latest

# კონკრეტული IP მისამართის კონფიგურაცია (სასარგებლოა სერვისებისთვის, რომლებიც ფიქსირებულ IP-ებს ელიან)
docker run -d --ip 172.17.0.10 my-app:latest

# გამოიყენეთ კონკრეტული ქსელის დრაივერი წარმადობისთვის
docker network create --driver=bridge --subnet=172.28.0.0/16 --gateway=172.28.0.1 \
  --ip-range=172.28.5.0/24 --aux-address="my-router=172.28.1.5" \
  -o "com.docker.network.bridge.enable_icc=true" \
  -o "com.docker.network.driver.mtu=1500" \
  my-network

# შეამცირეთ პორტების დიაპაზონი კონკრეტული სერვისებისთვის
docker run -d --sysctl net.ipv4.ip_local_port_range="10000 10500" my-app:latest

# TCP პარამეტრების რეგულირება მაღალი წარმადობის სამუშაო დატვირთვებისთვის
docker run -d \
  --sysctl net.core.somaxconn=1024 \
  --sysctl net.ipv4.tcp_max_syn_backlog=1024 \
  --sysctl net.ipv4.tcp_fin_timeout=30 \
  --sysctl net.ipv4.tcp_keepalive_time=300 \
  my-app:latest

ქსელის რეჟიმის მოსაზრებები:

  • bridge: ნაგულისხმევი რეჟიმი, უზრუნველყოფს იზოლაციას NAT-ით (მცირე ზედნადები)
  • host: იზიარებს ჰოსტის ქსელის სტეკს (საუკეთესო წარმადობა, შემცირებული იზოლაცია)
  • overlay: მრავალ-ჰოსტიანი ქსელი, უფრო მაღალი ზედნადები, მაგრამ აუცილებელია swarm-ისთვის
  • macvlan: ანიჭებს MAC მისამართს კონტეინერს (თითქმის მშობლიური წარმადობა)
  • none: ქსელური კავშირის გარეშე, უმაღლესი იზოლაცია

წარმადობაზე მოქმედი ფაქტორები:

  • კონტეინერებს შორის კომუნიკაციის ზედნადები
  • NAT წარმადობა მაღალი გამტარუნარიანობის სერვისებზე
  • DNS რეზოლუციის შეყოვნება
  • MTU-ს შეუსაბამობა, რომელიც იწვევს ფრაგმენტაციას
  • ქსელის დრაივერის იმპლემენტაციის განსხვავებები

საცავის ოპტიმიზაცია

მეხსიერების მართვა

მეხსიერების სათანადო მართვა კრიტიკულია კონტეინერის სტაბილურობის, ჰოსტის დაცვისა და რესურსების ეფექტური გამოყენებისთვის. მეხსიერების ლიმიტების გარეშე კონტეინერებს შეუძლიათ მოიხმარონ მთელი ხელმისაწვდომი სისტემის მეხსიერება, რაც იწვევს არასტაბილურობას.

მეხსიერების ლიმიტები

  • დააყენეთ შესაბამისი მეხსიერების ლიმიტები
    • აპლიკაციის პროფაილირებაზე დაყრდნობით და არა ვარაუდით
    • ჩართეთ ზღვარი garbage collection-ისა და პიკური გამოყენებისთვის
    • გაითვალისწინეთ როგორც resident set size (RSS), ასევე ვირტუალური მეხსიერება
    • დააბალანსეთ ზედმეტად შემზღუდველ (ავარიები) და ზედმეტად გულუხვ (დანაკარგი) ლიმიტებს შორის
    • მაგალითი: --memory=512m --memory-reservation=384m
    • სხვადასხვა აპლიკაციას აქვს მეხსიერების გამოყენების სხვადასხვა ნიმუში:
      • JVM: გაითვალისწინეთ heap ზომა + metaspace + მშობლიური მეხსიერება
      • Node.js: V8 heap + ბუფერების განაწილება
      • Python: ინტერპრეტატორის ზედნადები + აპლიკაციის მეხსიერება
  • დააკონფიგურირეთ swap-ის ქცევა
    • --memory-swap: მთლიანი მეხსიერება+swap ლიმიტი
    • --memory-swappiness=0: შეამცირეთ swap-ი მინიმუმამდე
    • მთლიანად გამორთეთ swap შეყოვნება-მგრძნობიარე აპლიკაციებისთვის
    • მონაცემთა ბაზებისთვის, დააკონფიგურირეთ შესაბამისი swappiness
    • მაგალითი: --memory=1g --memory-swap=1g (swap-ის გარეშე)
  • დააკვირდეთ მეხსიერების გამოყენებას
    • თვალყური ადევნეთ როგორც მიმდინარე, ასევე პიკურ მეხსიერების გამოყენებას
    • იდენტიფიცირეთ მეხსიერების გაჟონვა ტრენდული მონაცემებით
    • დააკვირდეთ garbage collection-ის სიხშირესა და ხანგრძლივობას
    • გააანალიზეთ OOM kill მოვლენები
    • ინსტრუმენტები: docker stats, cAdvisor, Prometheus მეტრიკები
    • ბრძანებები:
      # ცოცხალი მეხსიერების გამოყენება
      docker stats --no-stream --format "table {{.Name}}\t{{.MemUsage}}"
      
      # კონტეინერის მეხსიერების დეტალები
      docker inspect $(docker ps -q) | jq '.[].HostConfig.Memory'
      
  • გამოიყენეთ cgroup შეზღუდვები
    • ბირთვის მეხსიერების ლიმიტები: --kernel-memory=64m
    • CPU-სა და მეხსიერების წნევის კორელაცია
    • რბილი vs მყარი ლიმიტები: რეზერვაცია vs ლიმიტი
    • cgroup v2 მხარდაჭერა გაუმჯობესებული მეხსიერების აღრიცხვისთვის
    • მაგალითი: --memory-reservation=256m --memory=512m
  • დანერგეთ OOM დამუშავება
    • --oom-kill-disable: თავიდან აიცილეთ OOM killer (გამოიყენეთ სიფრთხილით)
    • --oom-score-adj: დაარეგულირეთ OOM kill პრიორიტეტი (-1000-დან 1000-მდე)
    • სათანადო აპლიკაციის დონის შეცდომების დამუშავება
    • კორექტული დეგრადაცია მეხსიერების წნევის ქვეშ
    • ჯანმრთელობის მონიტორინგი მეხსიერებასთან დაკავშირებული პრობლემების გამოსავლენად
    • OOM-ცნობიერი აპლიკაციის დიზაინი
    • მაგალითი: --oom-score-adj=-500 (ნაკლებად სავარაუდოა, რომ გაითიშოს)

მეხსიერების პარამეტრები Compose-ში

განსაზღვრეთ ყოვლისმომცველი მეხსიერების შეზღუდვები Docker Compose-ში განმეორებადი მრავალკონტეინერიანი deployment-ებისთვის:

version: '3.8'
services:
  app:
    image: my-app:latest
    deploy:
      resources:
        limits:
          memory: 512M  # მყარი ლიმიტი - კონტეინერი ითიშება გადაჭარბებისას
          cpus: '0.5'   # CPU ლიმიტები ხშირად მოქმედებს მეხსიერების გამოყენების ნიმუშებზე
        reservations:
          memory: 256M  # რბილი ლიმიტი - გარანტირებული მინიმალური მეხსიერება
          cpus: '0.25'  # გარანტირებული CPU რეზერვაცია
    environment:
      # აპლიკაცია-სპეციფიკური მეხსიერების პარამეტრები
      JAVA_OPTS: "-Xms256m -Xmx384m -XX:MaxMetaspaceSize=128m"
      NODE_OPTIONS: "--max-old-space-size=384"
    # დამატებითი მეხსიერებასთან დაკავშირებული პარამეტრები
    ulimits:
      memlock: -1  # შეუზღუდავი memlock მონაცემთა ბაზებისთვის
    # OOM პარამეტრები (მოითხოვს ჰოსტის პრივილეგიებს)
    oom_score_adj: 500  # მაღალი მნიშვნელობა = OOM killer-ის მიერ გათიშვის მაღალი შანსი
    # მეხსიერების swappiness კონტროლი (0-100)
    mem_swappiness: 0   # უპირატესობა მიანიჭეთ page cache-ის მოშორებას, ვიდრე მეხსიერების swap-ს
    # თუ იყენებთ compose-ს swarm-თან:
    restart_policy:
      condition: on-failure
      max_attempts: 3
      delay: 5s

  database:
    image: postgres:13
    deploy:
      resources:
        limits:
          memory: 1G
        reservations:
          memory: 512M
    environment:
      POSTGRES_PASSWORD: example
      # მონაცემთა ბაზის მეხსიერების რეგულირება
      POSTGRES_SHARED_BUFFERS: 256MB
      POSTGRES_EFFECTIVE_CACHE_SIZE: 768MB
      POSTGRES_WORK_MEM: 16MB

Production-ში გამოყენებისთვის, განიხილეთ ეს დამატებითი მეხსიერების ოპტიმიზაციის ტექნიკა:

  • JVM/runtime-სპეციფიური მეხსიერების დროშების დაყენება გარემოს ცვლადების საშუალებით
  • აპლიკაციის სერვერის პარამეტრების კორექტირება (workers, threads, connection pools)
  • მონაცემთა ბაზის მეხსიერების განაწილების პარამეტრების დაზუსტება
  • კორექტული დეგრადაციის დანერგვა მეხსიერების წნევის ქვეშ
  • health check-ების გამოყენება, რომლებიც აკვირდებიან მეხსიერების გამოყენებას

მეხსიერების მონიტორინგი

მეხსიერების ყოვლისმომცველი მონიტორინგი ეხმარება პრობლემების იდენტიფიცირებას, სანამ ისინი შეფერხებებს გამოიწვევენ და უზრუნველყოფს მონაცემებს სათანადო ზომის დასადგენად:

# კონტეინერის მეხსიერების გამოყენების შემოწმება ლამაზი ცხრილის ფორმატით
docker stats --no-stream --format "table {{.Name}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.CPUPerc}}"

# დეტალური მეხსიერების სტატისტიკის მიღება JSON ფორმატში დამუშავებისთვის
docker stats --no-stream --format "{{json .}}" container_name | jq '.'

# კონკრეტული მეხსიერების მეტრიკების ამოღება
docker stats --no-stream --format "{{.MemUsage}}" container_name | awk '{print $1}'

# მეხსიერების გამოყენების მონიტორინგი დროთა განმავლობაში (ნიმუშები ყოველ 5 წამში)
while true; do 
  docker stats --no-stream --format "{{.Name}},{{.MemUsage}},{{.MemPerc}}" >> memory_log.csv
  sleep 5
done

# ბირთვის მეხსიერების მოვლენების შემოწმება (OOM kill-ები)
dmesg | grep -i "out of memory"

# კონტეინერის მეხსიერების ლიმიტების შემოწმება
docker inspect --format '{{.HostConfig.Memory}}' container_name

# დეტალური მეხსიერების მეტრიკებისთვის, გამოიყენეთ cAdvisor ან Prometheus
# თვალყურის დევნების მეტრიკების მაგალითი:
# - container_memory_usage_bytes
# - container_memory_cache
# - container_memory_rss
# - container_memory_swap
# - container_memory_failcnt (მეხსიერების ლიმიტის დარტყმის რაოდენობა)
# - container_memory_mapped_file

# კონტეინერების პოვნა მეხსიერების ლიმიტების გარეშე
docker ps -q | xargs docker inspect -f '{{.Name}} {{.HostConfig.Memory}}' | grep " 0$"

# მეხსიერების რეზერვაციის შედარება ფაქტობრივ გამოყენებასთან
docker ps -q | xargs docker inspect -f '{{.Name}}: Limit={{.HostConfig.Memory}} Reservation={{.HostConfig.MemoryReservation}}' | sort

მეხსიერების ანალიზის გაფართოებული ინსტრუმენტები:

  • cAdvisor დეტალური კონტეინერის მეხსიერების მეტრიკებისთვის
  • Prometheus + Grafana ვიზუალიზაციისა და შეტყობინებებისთვის
  • docker-top პროცესის დონის მეხსიერების ხილვადობისთვის კონტეინერებში
  • memory-profiler აპლიკაცია-სპეციფიური მეხსიერების ანალიზისთვის
  • pmap პროცესის მეხსიერების მიბმისთვის (მოითხოვს პრივილეგირებულ წვდომას)

მეხსიერების გამოყენების ნიმუშები

CPU-ს ოპტიმიზაცია

CPU-ს სათანადო მართვა უზრუნველყოფს რესურსების სამართლიან განაწილებას, პროგნოზირებად წარმადობასა და ეფექტურ ჰოსტის გამოყენებას:

# CPU-ს გამოყენების შეზღუდვა (აბსოლუტური ლიმიტი ბირთვების რაოდენობაში)
docker run -d --cpus=0.5 my-app:latest

# CPU-ს წილების დაყენება (შედარებითი პრიორიტეტის წონა, ნაგულისხმევია 1024)
# მაღალი მნიშვნელობები იღებენ მეტ CPU დროს კონკურენციისას
docker run -d --cpu-shares=512 my-app:latest

# კონკრეტულ CPU-ებზე მიბმა (სასარგებლოა NUMA არქიტექტურებისთვის ან CPU-მგრძნობიარე დატვირთვებისთვის)
docker run -d --cpuset-cpus="0,1" my-app:latest

# რეალურ დროში დაგეგმვის პრიორიტეტის კონფიგურაცია (მოითხოვს პრივილეგირებულ წვდომას)
docker run -d --cpu-rt-runtime=950000 --cpu-rt-period=1000000 my-app:latest

# CPU-ს დაგეგმვის პრიორიტეტის დაყენება nice მნიშვნელობით
docker run -d --cpu-shares=1024 --pids-limit=100 my-app:latest

# CPU CFS (Completely Fair Scheduler) პერიოდის შეზღუდვა
docker run -d --cpu-period=100000 --cpu-quota=50000 my-app:latest

# რთული მაგალითი მრავალი CPU შეზღუდვით
docker run -d \
  --cpus=1.5 \
  --cpu-shares=1024 \
  --cpuset-cpus="0,2,4" \
  --cpu-period=100000 \
  --cpu-quota=150000 \
  high-priority-app:latest

CPU-ს განაწილების ოფციების გაგება:

  • cpus: მარტივი აბსოლუტური ლიმიტი (მაგ., 0.5 = ნახევარი CPU ბირთვი)
  • cpu-shares: შედარებითი წონა კონკურენციისას (არ აქვს ეფექტი, როდესაც CPU უხვადაა)
  • cpuset-cpus: მყარი მიბმა კონკრეტულ CPU ბირთვებზე
  • cpu-period/cpu-quota: დეტალური CFS კონტროლი (quota/period = CPU ლიმიტი)

CPU-ს ოპტიმიზაციის მოსაზრებები:

  • შეუსაბამეთ CPU ლიმიტები აპლიკაციის საჭიროებებს პროფაილირებაზე დაყრდნობით
  • გაითვალისწინეთ NUMA ეფექტები მეხსიერება-ინტენსიური აპლიკაციებისთვის
  • დააბალანსეთ იზოლაცია და რესურსების ეფექტური გამოყენება
  • დააკვირდეთ CPU-ს შეზღუდვის მეტრიკებს არასწორი კონფიგურაციის გამოსავლენად
  • განიხილეთ CPU affinity ქეშ-მგრძნობიარე დატვირთვებისთვის
  • დააყენეთ შესაბამისი ლიმიტები როგორც პიკური, ასევე მდგრადი დატვირთვებისთვის

Docker Daemon-ის ოპტიმიზაცია

თავად Docker daemon-ი შეიძლება დარეგულირდეს უკეთესი წარმადობის, უსაფრთხოებისა და რესურსების გამოყენებისთვის. ეს პარამეტრები გავლენას ახდენს ჰოსტზე არსებულ ყველა კონტეინერზე.

Daemon-ის კონფიგურაცია

შეცვალეთ /etc/docker/daemon.json გლობალური პარამეტრების კონფიგურაციისთვის:

{
  "default-ulimits": {
    "nofile": {
      "Name": "nofile",
      "Hard": 64000,
      "Soft": 64000
    },
    "nproc": {
      "Name": "nproc",
      "Hard": 32768,
      "Soft": 32768
    }
  },
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3",
    "compress": "true"
  },
  "max-concurrent-downloads": 10,
  "max-concurrent-uploads": 10,
  "storage-driver": "overlay2",
  "storage-opts": [
    "overlay2.override_kernel_check=true",
    "overlay2.size=20G"
  ],
  "registry-mirrors": [
    "https://mirror.gcr.io",
    "https://registry-1.docker.io"
  ],
  "dns": ["8.8.8.8", "8.8.4.4"],
  "default-address-pools": [
    {"base": "172.30.0.0/16", "size": 24}
  ],
  "experimental": true,
  "metrics-addr": "0.0.0.0:9323",
  "features": {
    "buildkit": true
  },
  "live-restore": true,
  "default-runtime": "runc",
  "exec-opts": ["native.cgroupdriver=systemd"],
  "init": true,
  "no-new-privileges": true,
  "icc": false
}

მნიშვნელოვანი daemon-ის პარამეტრები გასათვალისწინებლად:

  • storage-driver: შეარჩიეთ შესაბამისი დრაივერი სამუშაო დატვირთვისთვის (overlay2 რეკომენდებულია)
  • live-restore: შეინარჩუნეთ კონტეინერები გაშვებული daemon-ის გადატვირთვისას
  • max-concurrent-downloads/uploads: დაარეგულირეთ ქსელისა და დისკის I/O-ს მიხედვით
  • registry-mirrors: დააყენეთ pull-through ქეში ხშირად გამოყენებული image-ებისთვის
  • default-runtime: შეარჩიეთ კონტეინერის runtime (runc, containerd და ა.შ.)
  • init: ყოველთვის გამოიყენეთ init პროცესი უკეთესი სიგნალების დამუშავებისა და zombie-ების თავიდან აცილებისთვის
  • icc: კონტეინერებს შორის კომუნიკაციის კონტროლი (false უკეთესი უსაფრთხოებისთვის)
  • default-ulimits: დააყენეთ შესაბამისი ფაილების დესკრიპტორისა და პროცესის ლიმიტები
  • metrics-addr: ჩართეთ Prometheus მეტრიკების ენდფოინთი

ლოგირების კონფიგურაცია

  • გამოიყენეთ შესაბამისი ლოგ დრაივერები
    • json-file: ნაგულისხმევი, ინახავს ლოგებს JSON ფაილებად ჰოსტზე
    • local: ახალი ოპტიმიზირებული ლოკალური ლოგირების დრაივერი
    • syslog: გადაგზავნა syslog daemon-თან
    • journald: გადაგზავნა systemd journal-თან
    • splunk, awslogs, gelf: გაგზავნა გარე ლოგირების სისტემებში
    • none: ლოგირების გამორთვა წარმადობა-კრიტიკული აპლიკაციებისთვის
  • დააკონფიგურირეთ ლოგების როტაცია
    • დააყენეთ max-size ინდივიდუალური ლოგ ფაილის ზომის შესაზღუდად
    • დააყენეთ max-file შესანახი ლოგ ფაილების რაოდენობის გასაკონტროლებლად
    • ჩართეთ compress დისკის გამოყენების შესამცირებლად
    • განიხილეთ დროზე დაფუძნებული როტაცია შესაბამისობის მოთხოვნებისთვის
    • დანერგეთ ჰოსტის დონის ლოგების მართვა Docker-ის საკუთარი ლოგებისთვის
  • განიხილეთ ცენტრალიზებული ლოგირება
    • მოახდინეთ კონტეინერის ლოგების აგრეგაცია Elasticsearch-ში, Splunk-ში ან მსგავს სისტემაში
    • დანერგეთ სტრუქტურირებული ლოგირება უკეთესი ძებნადობისთვის
    • დააკონფიგურირეთ სათანადო შენახვის პოლიტიკები სხვადასხვა ტიპის ლოგებისთვის
    • დააყენეთ მონიტორინგი და შეტყობინებები ლოგების ნიმუშებზე დაყრდნობით
    • შეინახეთ ლოგები ეფემერული კონტეინერებიდან
  • შეზღუდეთ ლოგ ფაილის ზომა
    • თავიდან აიცილეთ დისკის სივრცის გამოფიტვა "მოლაპარაკე" კონტეინერებისგან
    • დააყენეთ შესაბამისი ლიმიტები აპლიკაციის სიტყვაუხვიანობის მიხედვით
    • დააკვირდეთ ლოგების მოცულობასა და ზრდის ტემპს
    • შეატყობინეთ ლოგების მოცულობის უჩვეულო ზრდაზე
    • დანერგეთ საგანგებო გასუფთავება უკონტროლო ლოგირებისთვის
  • აკონტროლეთ ლოგირების სიტყვაუხვიანობა
    • დააკონფიგურირეთ აპლიკაციის ლოგების დონეები შესაბამისად
    • გაფილტრეთ არარელევანტური ლოგები შენახვამდე
    • დანერგეთ ნიმუშების აღება მაღალი მოცულობის ლოგების წყაროებისთვის
    • გამოიყენეთ გარემოს ცვლადები ლოგების სიტყვაუხვიანობის გასაკონტროლებლად
    • განიხილეთ სხვადასხვა სიტყვაუხვიანობა სხვადასხვა გარემოსთვის

სისტემის დონის ოპტიმიზაციები

  • გაზარდეთ ფაილების დესკრიპტორების ლიმიტები ჰოსტ OS-ში
  • დააკონფიგურირეთ შესაბამისი I/O scheduler-ი საცავის მოწყობილობებისთვის
  • დაარეგულირეთ ბირთვის პარამეტრები კონტეინერის დატვირთვებისთვის:
    # /etc/sysctl.conf კორექტირებები
    fs.file-max = 2097152
    fs.inotify.max_user_watches = 524288
    vm.max_map_count = 262144
    net.ipv4.ip_forward = 1
    
  • გამორთეთ SWAP პროგნოზირებადი კონტეინერის წარმადობისთვის
  • გამოიყენეთ მაღალი წარმადობის საცავი Docker-ის მონაცემთა დირექტორიისთვის
  • დააკონფიგურირეთ შესაბამისი CPU governor-ი სამუშაო დატვირთვის ტიპისთვის

Development-ის ოპტიმიზაცია

Production-ის ოპტიმიზაცია

Production გარემოსთვის, მოახდინეთ კონტეინერების ოპტიმიზაცია საიმედოობის, უსაფრთხოების, წარმადობისა და დაკვირვებადობისთვის:

version: '3.8'
services:
  optimized-app:
    image: my-app:latest
    # მაღალი ხელმისაწვდომობის პარამეტრები
    restart: unless-stopped
    deploy:
      replicas: 2
      update_config:
        parallelism: 1
        delay: 10s
        order: start-first
        failure_action: rollback
      rollback_config:
        parallelism: 1
        delay: 5s
      resources:
        limits:
          cpus: '0.50'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 128M
    
    # უსაფრთხოების გამკაცრება
    read_only: true
    tmpfs:
      - /tmp:size=64M,mode=1777
      - /var/cache:size=128M
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE
    security_opt:
      - no-new-privileges:true
      - seccomp=default.json
    
    # ჯანმრთელობის მონიტორინგი
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    
    # ეფექტური ლოგირება
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
        compress: "true"
        tag: "{{.Name}}/{{.ID}}"
    
    # ქსელის ოპტიმიზაცია
    dns:
      - 1.1.1.1
      - 8.8.8.8
    dns_opt:
      - timeout:3
      - attempts:5
    
    # აპლიკაციის რეგულირება
    environment:
      - NODE_ENV=production
      - SERVER_MAX_CONNECTIONS=1000
      - GOMAXPROCS=1
    ulimits:
      nofile:
        soft: 20000
        hard: 40000
    
    # დამოკიდებულების მართვა
    depends_on:
      database:
        condition: service_healthy
    
    # საიდუმლოებების მართვა
    secrets:
      - source: app_config
        target: /app/config.json
        mode: 0400
      - source: ssl_cert
        target: /app/cert.pem
        mode: 0400

  database:
    image: postgres:13
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 1G
        reservations:
          cpus: '0.5'
          memory: 512M
    volumes:
      - db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
      POSTGRES_DB: appdb
    secrets:
      - db_password

volumes:
  db-data:
    driver: local
    driver_opts:
      type: 'none'
      o: 'bind'
      device: '/mnt/data/postgres'

secrets:
  app_config:
    file: ./config/production.json
  ssl_cert:
    file: ./config/ssl/cert.pem
  db_password:
    file: ./config/secrets/db_password.txt

Production-ის ოპტიმიზაცია მოიცავს მრავალ განზომილებას:

  1. მაღალი ხელმისაწვდომობა: რეპლიკები, მოძრავი განახლებები, health check-ები
  2. უსაფრთხოება: მხოლოდ წაკითხვადი ფაილური სისტემა, მოშორებული შესაძლებლობები, seccomp პროფილები
  3. რესურსების მართვა: ზუსტი CPU/მეხსიერების ლიმიტები და რეზერვაციები
  4. დაკვირვებადობა: ლოგირება, health check-ები, მონიტორინგი
  5. წარმადობის რეგულირება: აპლიკაცია-სპეციფიური ოპტიმიზაციები
  6. დამოკიდებულების მართვა: სათანადო გაშვების რიგი და health check-ები
  7. საიდუმლოებების დამუშავება: რწმუნებათა სიგელებისა და სერტიფიკატების უსაფრთხო ინექცია
  8. მონაცემთა მდგრადობა: სათანადოდ კონფიგურირებული volume-ები შესაბამისი დრაივერებით

წარმადობის გაზომვა

სისტემატური წარმადობის გაზომვა აუცილებელია ოპტიმიზაციების ვალიდაციისა და ბოთლის ყელების იდენტიფიცირებისთვის. დანერგეთ ყოვლისმომცველი ბენჩმარკინგისა და მონიტორინგის პრაქტიკები კონტეინერის წარმადობის მახასიათებლების გასაგებად.

ბენჩმარკინგი

  • გამოიყენეთ Docker stats რეალურ დროში მეტრიკებისთვის
    # ცოცხალი მონიტორინგი მორგებული სვეტებით
    docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.NetIO}}\t{{.BlockIO}}"
    
    # დროის მომენტში სტატისტიკის დაჭერა
    docker stats --no-stream > stats-$(date +%Y%m%d-%H%M%S).txt
    
    # გაშვების დროის გაზომვა
    time docker run --name test-startup my-app:latest
    
  • დანერგეთ აპლიკაციის დონის მეტრიკები
    • ინსტრუმენტირება გაუკეთეთ კოდს Prometheus კლიენტის ბიბლიოთეკებით
    • გაზომეთ კრიტიკული ბიზნეს ოპერაციების შეყოვნება
    • თვალყური ადევნეთ რესურსების გამოყენებას აპლიკაციის შიგნიდან
    • დააკვირდეთ ქეშის დარტყმის სიხშირესა და მონაცემთა ბაზის მოთხოვნების წარმადობას
    • თვალყურის დევნების მეტრიკების მაგალითი:
      • მოთხოვნის შეყოვნების პროცენტილები (p50, p95, p99)
      • მოთხოვნის გამტარუნარიანობა (მოთხოვნები წამში)
      • შეცდომების სიხშირე და ტიპები
      • ბიზნეს ტრანზაქციები წამში
      • რიგის სიღრმეები და დამუშავების დროები
  • შეადარეთ ოპტიმიზაციებამდე და შემდეგ
    • შექმენით განმეორებადი ბენჩმარკის სცენარები
    • დაადოკუმენტირეთ საბაზისო წარმადობის მეტრიკები
    • იზოლირება გაუკეთეთ ცვლადებს ცვლილებების ტესტირებისას
    • გაზომეთ გავლენა როგორც საშუალო, ასევე კუდის შეყოვნებაზე
    • გაითვალისწინეთ ოპტიმიზაციების ხარჯები
    • ბენჩმარკინგის სამუშაო პროცესის მაგალითი:
      # დატვირთვის ტესტის გაშვება მიმდინარე ვერსიაზე
      ./load-test.sh --target=v1 --duration=10m > results-v1.txt
      
      # ოპტიმიზაციის გამოყენება
      docker build -t my-app:v2 -f Dockerfile.optimized .
      
      # იდენტური დატვირთვის ტესტის გაშვება ოპტიმიზირებულ ვერსიაზე
      ./load-test.sh --target=v2 --duration=10m > results-v2.txt
      
      # შედეგების შედარება
      ./compare-results.sh results-v1.txt results-v2.txt
      
  • თვალყური ადევნეთ build-ისა და გაშვების დროს
    • გაზომეთ სრული CI/CD მილსადენის ხანგრძლივობა
    • დაყავით build-ის ფაზები მიზნობრივი ოპტიმიზაციისთვის
    • თვალყური ადევნეთ image-ის pull-ის დროს სხვადასხვა გარემოში
    • გაზომეთ დრო პირველ მოთხოვნამდე აპლიკაციებისთვის
    • დააკვირდეთ ცივი და თბილი გაშვების წარმადობას
    • გაზომვის სკრიპტის მაგალითი:
      #!/bin/bash
      echo "Build-ის დრო:"
      time docker build -t test-app .
      
      echo "Image-ის ზომა:"
      docker images test-app --format "{{.Size}}"
      
      echo "Pull-ის დრო (სიმულაცია):"
      docker save test-app | wc -c | awk '{print $1/1024/1024 " MB"}'
      docker rmi test-app
      time docker load < test-app.tar
      
      echo "გაშვების დრო:"
      time docker run --rm test-app
      
  • გაზომეთ image-ების ზომები
    • თვალყური ადევნეთ ფენების შემადგენლობასა და ზომებს
    • შეადარეთ შეკუმშული და არაშეკუმშული image-ების ზომები
    • გააანალიზეთ image-ის შემადგენლობა ისეთი ინსტრუმენტებით, როგორიცაა dive
    • დააკავშირეთ image-ის ზომა pull-ის დროსთან
    • თვალყური ადევნეთ image-ის ზომის ევოლუციას დროთა განმავლობაში
    • ბრძანებების მაგალითი:
      # image-ის ძირითადი ზომა
      docker images my-app
      
      # დეტალური დაშლა dive-ით
      docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock wagoodman/dive:latest my-app:latest
      
      # ფენების ზომები და ისტორია
      docker history --no-trunc --format "table {{.CreatedBy}}\t{{.Size}}" my-app:latest
      
      # შეკუმშული ზომის გამოთვლა (მხოლოდ pull-ის ზომის მიახლოება)
      docker save my-app:latest | gzip -c | wc -c
      

მონიტორინგის ინსტრუმენტები

  • Docker stats: ძირითადი ჩაშენებული რესურსების მონიტორინგი
    # ყველა კონტეინერის უწყვეტი მონიტორინგი
    docker stats
    
    # მორგებული ფორმატი კონკრეტული მეტრიკებისთვის
    docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"
    
  • cAdvisor: კონტეინერ-სპეციფიური მეტრიკები ისტორიული მონაცემებით
    # cAdvisor კონტეინერის გაშვება
    docker run \
      --volume=/:/rootfs:ro \
      --volume=/var/run:/var/run:ro \
      --volume=/sys:/sys:ro \
      --volume=/var/lib/docker/:/var/lib/docker:ro \
      --publish=8080:8080 \
      --detach=true \
      --name=cadvisor \
      --privileged \
      --device=/dev/kmsg \
      gcr.io/cadvisor/cadvisor:v0.45.0
    
  • Prometheus: დროის სერიების მეტრიკების შენახვა და გამოთხოვა
    • შეაგროვეთ კონტეინერისა და ჰოსტის მეტრიკები
    • შეინახეთ ისტორიული წარმადობის მონაცემები
    • შექმენით შეტყობინებები წარმადობის ზღვრებზე დაყრდნობით
    • PromQL მაგალითები კონტეინერის მონიტორინგისთვის:
      # CPU-ს გამოყენება კონტეინერის მიხედვით
      rate(container_cpu_usage_seconds_total{name=~".+"}[1m])
      
      # მეხსიერების გამოყენება კონტეინერის მიხედვით
      container_memory_usage_bytes{name=~".+"}
      
      # დისკის I/O კონტეინერის მიხედვით
      rate(container_fs_reads_bytes_total{name=~".+"}[1m])
      
  • Grafana dashboards: ვიზუალიზაცია და დაფები
    • შექმენით მორგებული დაფები სხვადასხვა დაინტერესებული მხარეებისთვის
    • დააყენეთ შეტყობინებები წარმადობის ზღვრებზე დაყრდნობით
    • მოახდინეთ ტრენდების ვიზუალიზაცია დროთა განმავლობაში
    • დააკავშირეთ მეტრიკები სისტემის კომპონენტებს შორის
    • დაფის პანელების მაგალითი:
      • კონტეინერის CPU-სა და მეხსიერების გამოყენება
      • ქსელის I/O კონტეინერის მიხედვით
      • დისკის ოპერაციები და გამტარუნარიანობა
      • აპლიკაცია-სპეციფიური მეტრიკები
      • Health check-ის სტატუსი და ისტორია
  • Docker Desktop მეტრიკები: ლოკალური development-ის მონიტორინგი
    • რესურსების გამოყენების მონიტორინგი Docker Desktop-ში
    • კონტეინერის ინსპექტირება და პრობლემების მოგვარება
    • ქსელის ტრაფიკის ვიზუალიზაცია
    • დისკის გამოყენების ანალიზი
    • გაფართოების პლაგინები გაუმჯობესებული მონიტორინგისთვის
  • სპეციალიზებული მონიტორინგის ინსტრუმენტები
    • Sysdig: კონტეინერისა და სისტემის ღრმა მონიტორინგი
    • Datadog: კომერციული APM და ინფრასტრუქტურის მონიტორინგი
    • New Relic: აპლიკაციისა და ინფრასტრუქტურის წარმადობა
    • Dynatrace: სრული სტეკის მონიტორინგი AI შესაძლებლობებით
    • Elastic APM: ღია კოდის აპლიკაციის წარმადობის მონიტორინგი

გასუფთავება და მოვლა

რეგულარული გასუფთავება და მოვლა აუცილებელია ჯანსაღი Docker გარემოს შესანარჩუნებლად, დისკის სივრცის პრობლემების თავიდან ასაცილებლად და წარმადობის ოპტიმიზაციისთვის:

# გამოუყენებელი კონტეინერების წაშლა (გაჩერებული კონტეინერები)
docker container prune

# გამოუყენებელი image-ების წაშლა (dangling image-ები, რომლებსაც არცერთი კონტეინერი არ იყენებს)
docker image prune

# გამოუყენებელი image-ების უფრო აგრესიულად წაშლა (გამოუყენებელი თეგირებული image-ების ჩათვლით)
docker image prune -a

# გამოუყენებელი volume-ების წაშლა (რომლებსაც არცერთი კონტეინერი არ იყენებს)
docker volume prune

# გამოუყენებელი ქსელების წაშლა
docker network prune

# ყველა გამოუყენებელი ობიექტის წაშლა (კონტეინერები, image-ები, volume-ები, ქსელები)
docker system prune -a

# ყველა გამოუყენებელი ობიექტის წაშლა volume-ების ჩათვლით (გამოიყენეთ სიფრთხილით!)
docker system prune -a --volumes

# კონტეინერების წაშლა სტატუსის მიხედვით
docker rm $(docker ps -q -f status=exited)

# ძველი კონტეინერების წაშლა (შექმნილია ერთ კვირაზე მეტი ხნის წინ)
docker container prune --filter "until=168h"

# კონკრეტული image-ების გასუფთავება ნიმუშის მიხედვით
docker images | grep "pattern" | awk '{print $3}' | xargs docker rmi

# დისკის გამოყენების დეტალების ნახვა
docker system df -v

# დაგეგმილი გასუფთავების დაყენება (dangling რესურსების ყოველდღიური გასუფთავება)
cat > /etc/cron.daily/docker-cleanup << 'EOF'
#!/bin/bash
/usr/bin/docker container prune -f --filter "until=24h"
/usr/bin/docker image prune -f
/usr/bin/docker network prune -f --filter "until=24h"
EOF
chmod +x /etc/cron.daily/docker-cleanup

# უფრო კონსერვატიული ყოველკვირეული გასუფთავება (გამოუყენებელი image-ების ჩათვლით)
cat > /etc/cron.weekly/docker-deep-cleanup << 'EOF'
#!/bin/bash
/usr/bin/docker system prune -f
EOF
chmod +x /etc/cron.weekly/docker-deep-cleanup

# ლოგების როტაცია კონტეინერის ლოგებისთვის
cat > /etc/logrotate.d/docker-container-logs << 'EOF'
/var/lib/docker/containers/*/*.log {
    rotate 7
    daily
    compress
    missingok
    delaycompress
    copytruncate
}
EOF

# გასუფთავების სკრიპტი უსაფრთხოების შემოწმებებითა და რეპორტინგით
cat > /usr/local/bin/docker-smart-cleanup << 'EOF'
#!/bin/bash
set -e

echo "=== Docker-ის გასუფთავების ანგარიში ($(date)) ==="
echo "გასუფთავებამდე:"
docker system df

# 1 კვირაზე მეტი ხნის უმოქმედო კონტეინერების გაჩერება
idle_containers=$(docker ps -q -f status=running --format "{{.ID}} {{.CreatedAt}}" | awk '$2 <= "'$(date -d 'now - 1 week' +'%Y-%m-%d')'" {print $1}')
if [ -n "$idle_containers" ]; then
  echo "უმოქმედო კონტეინერების გაჩერება: $idle_containers"
  docker stop $idle_containers
fi

# გამოსული კონტეინერების წაშლა
docker container prune -f

# dangling image-ების წაშლა
docker image prune -f

# გამოუყენებელი ქსელების წაშლა
docker network prune -f

# დისკის გამოყენების შემოწმება
current_usage=$(df -h /var/lib/docker | awk 'NR==2 {print $5}' | sed 's/%//')
if [ "$current_usage" -gt 80 ]; then
  echo "მაღალი დისკის გამოყენება გამოვლინდა ($current_usage%), ღრმა გასუფთავების შესრულება..."
  # თეგირებული, მაგრამ 1 თვეზე მეტი ხნის გამოუყენებელი image-ები
  docker image prune -a -f --filter "until=720h"
fi

echo "გასუფთავების შემდეგ:"
docker system df

echo "Top 10 უდიდესი image-ი:"
docker images --format "{{.Size}}\t{{.Repository}}:{{.Tag}}" | sort -hr | head -n 10
EOF
chmod +x /usr/local/bin/docker-smart-cleanup

მოვლის საუკეთესო პრაქტიკები:

  1. რეგულარული გასუფთავება: დანერგეთ დაგეგმილი გასუფთავებები შესაბამისი ფილტრებით
  2. მონიტორინგი: დააყენეთ შეტყობინებები დისკის სივრცის გამოყენებაზე Docker დირექტორიებში
  3. იარუსიანი მიდგომა: გამოიყენეთ სხვადასხვა გასუფთავების სტრატეგიები გარემოს კრიტიკულობის მიხედვით
  4. შენახვის პოლიტიკები: განსაზღვრეთ, რამდენ ხანს შეინახოთ გამოუყენებელი რესურსები
  5. Image-ის სასიცოცხლო ციკლი: დაადგინეთ პოლიტიკები image-ების ვერსიონირებისა და გასუფთავებისთვის
  6. მნიშვნელოვანი მონაცემების სარეზერვო ასლის შექმნა: დარწმუნდით, რომ მნიშვნელოვანი მონაცემების მქონე volume-ები დარეზერვებულია
  7. Image-ების გამოყენების აუდიტი: რეგულარულად გადახედეთ, რომელი image-ები გამოიყენება აქტიურად
  8. ლოგების მართვა: დააკონფიგურირეთ სათანადო ლოგების როტაცია და შენახვა

გაფართოებული ოპტიმიზაციის ტექნიკები

ოპტიმიზაციის ჩამონათვალი

Docker-ის ოპტიმიზაციის ყოვლისმომცველი მიდგომა უნდა მოიცავდეს კონტეინერის სასიცოცხლო ციკლის ყველა ასპექტს, image-ის აგებიდან runtime წარმადობამდე.

Image-ის ოპტიმიზაცია

  • მრავალეტაპიანი build-ები
    • გამოყავით build-დროის და runtime დამოკიდებულებები
    • გამოიყენეთ შესაბამისი საბაზისო image-ები თითოეული ეტაპისთვის
    • დააკოპირეთ მხოლოდ აუცილებელი არტეფაქტები ეტაპებს შორის
    • განიხილეთ ცალკეული ეტაპები ტესტირებისა და production-ისთვის
  • მინიმალური საბაზისო image-ები
    • გამოიყენეთ მსუბუქი ვარიანტები (alpine, slim, distroless)
    • წაშალეთ არასაჭირო პაკეტები და ინსტრუმენტები
    • შეარჩიეთ შესაბამისი ბაზა თავსებადობის vs. ზომის მიხედვით
    • განიხილეთ მორგებული ორგანიზაციული საბაზისო image-ები
    • განაახლეთ საბაზისო image-ები უსაფრთხოებისთვის
  • ფენების ოპტიმიზაცია
    • გააერთიანეთ დაკავშირებული ოპერაციები ერთ RUN ინსტრუქციაში
    • დაალაგეთ ფენები ნაკლებად ხშირად ცვლადიდან ყველაზე ხშირად ცვლადამდე
    • გაასუფთავეთ პაკეტების მენეჯერის ქეშები იმავე ფენაში
    • გამოიყენეთ მრავალხაზიანი არგუმენტები წაკითხვადობისთვის
    • შეინარჩუნეთ ფენების რაოდენობა გონივრულ ფარგლებში (20-ზე ნაკლები)
  • სათანადო ქეშირება
    • გამოიყენეთ BuildKit-ის გაუმჯობესებული ქეშირება
    • გამოიყენეთ .dockerignore არასაჭირო კონტექსტის თავიდან ასაცილებლად
    • დაყავით დამოკიდებულებები და აპლიკაციის კოდი
    • განიხილეთ ქეშის ცხადი მიმაგრება დამოკიდებულებებისთვის
    • დანერგეთ registry-ზე დაფუძნებული ქეშირება CI/CD-სთვის
  • ეფექტური COPY და RUN
    • დააკოპირეთ მხოლოდ ის, რაც საჭიროა (მოერიდეთ COPY . .)
    • გამოიყენეთ wildcard ნიმუშები დაკავშირებული ფაილებისთვის
    • დანერგეთ ჯაჭვური ბრძანებები სათანადო გასუფთავებით
    • დააყენეთ შესაბამისი სამუშაო დირექტორიები
    • გამოიყენეთ ADD მხოლოდ მაშინ, როდესაც ამოღების ფუნქციონალია საჭირო

Build-ის ოპტიმიზაცია

  • BuildKit-ი ჩართულია
    • დააყენეთ DOCKER_BUILDKIT=1 გარემოს ცვლადი
    • დააკონფიგურირეთ daemon.json-ში სისტემის მასშტაბით გამოყენებისთვის
    • გამოიყენეთ BuildKit-სპეციფიური ფუნქციები, როდესაც მიზანშეწონილია
    • დანერგეთ SSH და საიდუმლოების მიმაგრება უსაფრთხო build-ებისთვის
    • გამოიყენეთ პარალელური ეტაპის შესრულება
  • დალაგებული ინსტრუქციები
    • განათავსეთ იშვიათად ცვლადი ბრძანებები პირველ რიგში
    • დააჯგუფეთ დაკავშირებული ბრძანებები ლოგიკურად
    • დაყავით გრძელი RUN ბრძანებები სტრატეგიულად
    • მოაწყვეთ მაქსიმალური ქეშის ეფექტურობისთვის
    • შეინარჩუნეთ წაკითხვადობა და შენარჩუნებადობა
  • Build-ის ქეშირება
    • დანერგეთ სათანადო ფენების ქეშირების სტრატეგია
    • გამოიყენეთ ქეშის მიმაგრებები პაკეტების მენეჯერებისთვის
    • განიხილეთ გარე ქეშის საცავი CI/CD-სთვის
    • დანერგეთ ქეშის გახურება ხშირად აგებული image-ებისთვის
    • პერიოდულად გაასუფთავეთ გამოუყენებელი ქეში
  • CI/CD ინტეგრაცია
    • დააკონფიგურირეთ შესაბამისი ქეშირება მილსადენებში
    • დანერგეთ მატრიცული build-ები, სადაც მიზანშეწონილია
    • გამოიყენეთ build არგუმენტები გარემო-სპეციფიური build-ებისთვის
    • დაათეგეთ image-ები მნიშვნელოვანი მეტამონაცემებით
    • დანერგეთ მოწყვლადობის სკანირება მილსადენში
  • პარალელური build-ები
    • დააპროექტეთ მრავალეტაპიანი build-ები პარალელიზაციისთვის
    • შეინარჩუნეთ ეტაპები დამოუკიდებელი, სადაც შესაძლებელია
    • გამოიყენეთ BuildKit-ის ავტომატური პარალელიზაცია
    • მოახდინეთ build ინფრასტრუქტურის შესაბამისი მასშტაბირება
    • დააკვირდეთ build-ის წარმადობის მეტრიკებს

Runtime-ის ოპტიმიზაცია

  • რესურსების ლიმიტები
    • დააყენეთ შესაბამისი CPU-სა და მეხსიერების შეზღუდვები
    • დააკონფიგურირეთ სათანადო swap-ის ქცევა
    • დანერგეთ რესურსების მონიტორინგი
    • გამოიყენეთ რესურსების რეზერვაციები ორკესტრაციაში
    • დააბალანსეთ რესურსების ეფექტურობა და საიმედოობა
  • სათანადო ქსელი
    • შეარჩიეთ შესაბამისი ქსელის დრაივერები
    • ოპტიმალურად დააკონფიგურირეთ DNS პარამეტრები
    • დანერგეთ კავშირების pooling
    • განიხილეთ service mesh რთული აპლიკაციებისთვის
    • დააკვირდეთ ქსელის წარმადობის მეტრიკებს
  • Volume-ის ოპტიმიზაცია
    • გამოიყენეთ შესაბამისი volume დრაივერები დატვირთვებისთვის
    • დანერგეთ ქეშირების სტრატეგიები მიმაგრებული volume-ებისთვის
    • დააკონფიგურირეთ სათანადო mount ოფციები
    • დააკვირდეთ volume-ის წარმადობას
    • განიხილეთ სპეციალიზებული საცავი I/O-ინტენსიური დატვირთვებისთვის
  • ლოგირების კონფიგურაცია
    • შეარჩიეთ შესაბამისი ლოგირების დრაივერები
    • დანერგეთ ლოგების როტაცია და ზომის ლიმიტები
    • განიხილეთ სტრუქტურირებული ლოგირების ფორმატები
    • დააკონფიგურირეთ ცენტრალიზებული ლოგირება
    • დანერგეთ ლოგების დონის მართვა
  • მონიტორინგის დაყენება
    • განათავსეთ ყოვლისმომცველი კონტეინერის მონიტორინგი
    • დანერგეთ health check-ები
    • დააკონფიგურირეთ შეტყობინებები რესურსების შეზღუდვებზე
    • თვალყური ადევნეთ აპლიკაცია-სპეციფიკურ მეტრიკებს
    • დანერგეთ tracing განაწილებული სისტემებისთვის

წარმადობის პრობლემების მოგვარება