המרת VM ל-Docker/K8s: קונטיינריזציה עם אחריות

העברת יישום ממכונות וירטואליות לקונטיינרים מביאה לעיתים קרובות לבעיות בלתי צפויות: קוד legacy, תלויות נסתרות וסביבה ש'עבדה רק על השרת'. אנחנו עוזרים לך לנווט בנתיב הזה ללא כאבים—אנחנו מבצעים audit, הופכים שירותים לקונטיינרים ומפרסים אותם ב-Docker או Kubernetes. הצוות שלנו מוסר את הפרויקט turnkey, החל ממיפוי ה-VMs ועד להשקה מסודרת, תוך הבטחת פעילות יציבה ותמיכה מתמשכת.

היכולות שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1359
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1330
  • עיצוב לוגו לחברת B2B Advance
    עיצוב לוגו לחברת B2B Advance
    776
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1077
  • פיתוח לוגו חברת AIDER
    פיתוח לוגו חברת AIDER
    1022
  • פיתוח CRM עבור Chasseurs
    פיתוח CRM עבור Chasseurs
    1113

העברה ממכונות וירטואליות לקונטיינרים (VM → Docker/K8s)

העברת אפליקציה מ-VM לקונטיינרים היא משימה שכל צוות פוגש במוקדם או במאוחר. בניסיון שלנו, ראינו כיצד אפליקציות legacy שרצו שנים על שרתים ייעודיים נשברו בקונטיינרים בגלל תלויות לא ברורות. המהנדסים שלנו עזרו לעשרות לקוחות לקצר את זמן הפריסה פי 3 ולחסל בעיות סביבה. להלן מתודולוגיה שלב-אחר-שלב שהוכחה על פרויקטים עם 50+ מיקרוסרוויסים.

למה קונטיינריזציה עדיפה על פני VM

VM דורשת התקנת מערכת הפעלה, הגדרת מאגרי חבילות, עדכוני קרנל—באופן ידני או דרך Ansible. קונטיינר נבנה פעם אחת ורץ בכל מקום. לפי הנתונים שלנו, פיתוח על קונטיינרים מאיץ מחזורי CI/CD ב-40%. ב-Kubernetes מקבלים autoscaling (HPA/VPA), ריפוי עצמי, ועדכונים מתגלגלים מובנים. בנוסף, חיסכון ברישיונות מערכת הפעלה מסתכם בהפחתה של 30–50% בעלויות התשתית.

התחלה עם מלאי VM

לפני כתיבת ה-Dockerfile הראשון, צריך להבין בדיוק מה רץ על ה-VM. לעיתים קרובות, מכונת ייצור אחת מאחסנת: nginx כ-reverse proxy, האפליקציה עצמה (Node.js), PostgreSQL, Redis, עבודת cron לגיבויים, וסוכן דואר מקומי Postfix. אלה שבעה קונטיינרים נפרדים אם עושים זאת נכון.

# Что запущено на VM
systemctl list-units --type=service --state=running
ps auxf | grep -v grep

# Какие порты слушают
ss -tlnp

# Какие крон-задачи
crontab -l
ls /etc/cron.d/ /etc/cron.daily/

# Зависимости приложения (пример для Node.js)
cat package.json | jq '.dependencies | keys[]'
node --version; npm --version

התוצאה של המלאי היא רשימה של כל מה שצריך להעביר, עם הבנה של התלויות בין הרכיבים.

מלכודות טיפוסיות ב-Dockerfile

לוגים. האפליקציה כותבת ל-# Что запущено на VM systemctl list-units --type=service --state=running ps auxf | grep -v grep # Какие порты слушают ss -tlnp # Какие крон-задачи crontab -l ls /etc/cron.d/ /etc/cron.daily/ # Зависимости приложения (пример для Node.js) cat package.json | jq '.dependencies | keys[]' node --version; npm --version . בקונטיינר, לוגים חייבים ללכת ל-stdout/stderr—אחרת Docker daemon, Fluentd, או Loki לא יאספו אותם. אפשרות אחת: להוסיף קישור סימלי /var/log/app/access.log ב-Dockerfile. אפשרות טובה יותר: לתקן את הגדרות הלוגינג של האפליקציה עצמה.

הגדרה דרך משתני סביבה. נתיב קשיח ln -sf /dev/stdout /var/log/app/access.log חייב להיות מוחלף במשתני ENV או בהרכבת volume. Twelve-Factor App הוא לא רק קונספט אופנתי—זו דרישה לפעולה תקינה ב-K8s.

משתמשים והרשאות. האפליקציה רצה כ-root על ה-VM. בקונטיינר, זו סיכון אבטחתי. הוסף משתמש לא-מורשה:

FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

FROM node:20-alpine
RUN addgroup -g 1001 appgroup && adduser -u 1001 -G appgroup -s /bin/sh -D appuser
WORKDIR /app
COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules
COPY --chown=appuser:appgroup . .
USER appuser
EXPOSE 3000
CMD ["node", "server.js"]

מערכת init. האפליקציה משתמשת ב-supervisord או יוצרת תהליכי ילד ישירות. בקונטיינר, PID 1 חייב לטפל נכון ב-SIGTERM ולהעביר אותות לתהליכי הילד. אם האפליקציה לא יכולה, השתמש ב-tini כ-init:

RUN apk add --no-cache tini
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["node", "server.js"]

נתונים עם מצב (Stateful). האפליקציה כותבת קבצים שהועלו ל-/etc/app/config.yaml. בקונטיינר, זה חייב להיות מועבר ל-PersistentVolume (K8s) או להיות מורכב דרך FROM node:20-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci --only=production FROM node:20-alpine RUN addgroup -g 1001 appgroup && adduser -u 1001 -G appgroup -s /bin/sh -D appuser WORKDIR /app COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules COPY --chown=appuser:appgroup . . USER appuser EXPOSE 3000 CMD ["node", "server.js"] (Docker). נתונים לא חייבים לחיות בתוך הקונטיינר.

מניפסט Kubernetes טיפוסי

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-backend
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: backend
  template:
    metadata:
      labels:
        app: backend
    spec:
      securityContext:
        runAsNonRoot: true
        runAsUser: 1001
        fsGroup: 1001
      containers:
        - name: backend
          image: registry.internal/app-backend:1.2.3
          ports:
            - containerPort: 3000
          env:
            - name: DATABASE_URL
              valueFrom:
                secretKeyRef:
                  name: app-secrets
                  key: database-url
            - name: REDIS_URL
              value: "redis://redis-service:6379"
          resources:
            requests:
              cpu: 200m
              memory: 256Mi
            limits:
              cpu: 1000m
              memory: 512Mi
          livenessProbe:
            httpGet:
              path: /health
              port: 3000
            initialDelaySeconds: 30
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /ready
              port: 3000
            initialDelaySeconds: 5
            periodSeconds: 5
          volumeMounts:
            - name: uploads
              mountPath: /app/uploads
      volumes:
        - name: uploads
          persistentVolumeClaim:
            claimName: app-uploads-pvc

משאבים חסרים הם אחת הטעויות הנפוצות ביותר בפריסה הראשונה ל-K8s. ללא limits, pod יכול לצרוך את כל הזיכרון על הצומת; ללא requests, ה-scheduler לא יכול לחלק pods בצורה נכונה.

Cron Jobs → CronJob

cron מערכתי מועבר ל-K8s CronJob:

---
apiVersion: batch/v1
kind: CronJob
metadata:
  name: db-backup
spec:
  schedule: "0 2 * * *"
  concurrencyPolicy: Forbid
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers:
            - name: backup
              image: registry.internal/db-backup:latest
              env:
                - name: DATABASE_URL
                  valueFrom:
                    secretKeyRef:
                      name: app-secrets
                      key: database-url

RUN apk add --no-cache tini ENTRYPOINT ["/sbin/tini", "--"] CMD ["node", "server.js"] מונע התחלת עבודה חדשה אם הקודמת עדיין רצה.

הבטחת אמינות במהלך ההעברה

אנו מבטיחים שאחרי המעבר כל מדדי SLO המרכזיים יהיו תחת שליטה. הגדרת ניטור Prometheus+Grafana היא חלק מהחבילה הסטנדרטית. כל התצורות מנוהלות בגרסאות ב-Git—זה מבטל את הסיכון לאובדן שינויים. הצוות שלנו מורכב ממנהלי Kubernetes מוסמכים ומהנדסי ענן עם ניסיון של 10+ שנים. השלמנו מעל 30 העברות מוצלחות עבור מוצרי fintech, מסחר אלקטרוני ו-SaaS.

קריטריון VM קונטיינרים (Docker/K8s)
זמן אתחול 30–60 שניות 1–2 שניות
ניצול משאבים מערכת הפעלה כבדה, בידוד hypervisor תהליך קל, קרנל משותף
עלות (TCO) גבוהה יותר בגלל רישיונות ו-over-provisioning נמוכה ב-30–50% דרך מיקום קומפקטי

מה כולל שירות ההעברה שלנו

  • ביקורת תשתית VM ומפת תלויות
  • Dockerfile לכל מיקרוסרוויס עם build רב-שלבי
  • Helm charts לפריסת K8s
  • הגדרת CI/CD (GitLab CI / GitHub Actions)
  • ניטור והתראות (Prometheus, Loki, Grafana)
  • תיעוד תפעולי ו-runbook
  • העברת ידע לצוות הלקוח (הדרכה של 1–2 ימים)

באיזו אסטרטגיית העברה לבחור?

הרצף הנכון לאפליקציית ייצור:

  1. קונטיינריזציה — כתיבת Dockerfile, בדיקה מקומית
  2. CI לתמונה — בנייה ודחיפה ל-registry בכל merge ל-main
  3. פריסה ל-staging על K8s, הרצת בדיקות
  4. ריצה מקבילה — ה-VM הישן וה-pods החדשים רצים במקביל, התעבורה נשארת על ה-VM
  5. העברת תעבורה — Ingress או DNS מצביעים על K8s Service
  6. תצפית — שבוע בייצור, השוואת מדדים לבסיס
  7. הורדת VM משימוש — לאחר אישור יציבות

לעולם אל תעביר תעבורה ותכבה את ה-VM באותו זמן. זה נראה מובן מאליו, אבל בלחץ של דדליין, קל לשכוח.

מוכנים להתחיל את ההעברה? קבלו ייעוץ עם המהנדס שלנו.

לוחות זמנים

מורכבות האפליקציה זמן קונטיינריזציה זמן העברת K8s
פשוטה (תהליך 1, ללא מצב) 1–2 ימים 2–3 ימים
בינונית (2–3 רכיבים, עם מצב) 3–5 ימים שבוע
מורכבת (5+ רכיבים, תלויות legacy) 1–2 שבועות 2–4 שבועות

ביקורת תשתית VM ראשונית והערכה אורכים 1–2 ימים. לוחות זמנים סופיים נקבעים לאחר מכן. הזמינו ביקורת על תשתית ה-VM שלכם—נכין תוכנית העברה תוך 1–2 ימים.