Модуль 1.1: Образи контейнерів
Складність:
[MEDIUM]— Потребує розуміння Dockerfile та реєстрів образівЧас на виконання: 45–60 хвилин
Передумови: Модуль 0.2 (Робочий процес розробника), базові знання Docker
Що ви зможете робити
Розділ «Що ви зможете робити»Після завершення цього модуля ви зможете:
- Створити Dockerfile, що відповідає найкращим практикам щодо розміру, безпеки та кешування шарів
- Налаштувати політики витягування образів та облікові дані реєстру для специфікацій Підів
- Діагностувати помилки витягування образів, включно з
ImagePullBackOffта помилками автентифікації - Пояснити стратегії тегування образів і чому
:latestє небезпечним у продакшені
Чому цей модуль важливий
Розділ «Чому цей модуль важливий»Kubernetes не запускає вихідний код — він запускає образи контейнерів. Перш ніж будь-який застосунок потрапить до кластера, його потрібно запакувати в образ. CKAD очікує, що ви розумієте, як образи збираються, тегуються, завантажуються та посилаються.
Хоча під час іспиту ви не будете збирати складні образи (немає часу), вам потрібно:
- Розуміти основи Dockerfile
- Знати конвенції іменування образів
- Виправляти типові проблеми, пов’язані з образами
- Модифікувати наявні образи за потреби
Аналогія з морськими контейнерами
До контейнеризації перевезення товарів було хаосом. Кожен порт обробляв вантаж по-різному. Потім з’явився стандартизований морський контейнер — однакові розміри скрізь, можна штабелювати, працює на будь-якому кораблі. Образи контейнерів — та сама ідея для програмного забезпечення. Ваш застосунок, його залежності, його конфігурація — все запаковано у стандартний формат, який працює ідентично будь-де.
Конвенція іменування образів
Розділ «Конвенція іменування образів»Розуміння імен образів є критично важливим. Кожна специфікація Підa в Kubernetes посилається на образи:
[registry/][namespace/]image[:tag][@digest]| Компонент | Обов’язковий | Приклад | За замовчуванням |
|---|---|---|---|
| Реєстр | Ні | docker.io, gcr.io, quay.io | docker.io |
| Простір імен | Ні | library, mycompany | library |
| Образ | Так | nginx, myapp | - |
| Тег | Ні | latest, 1.19.0, alpine | latest |
| Дайджест | Ні | sha256:abc123... | - |
Приклади
Розділ «Приклади»# Повна специфікаціяimage: docker.io/library/nginx:1.21.0
# Еквівалентна скорочена форма (docker.io/library мається на увазі)image: nginx:1.21.0
# Інший реєстрimage: gcr.io/google-containers/nginx:1.21.0
# Власний простір іменimage: myregistry.com/myteam/myapp:v2.0.0
# З дайджестом (незмінне посилання)image: nginx@sha256:abc123def456...
# Тег latest (уникайте у продакшені)image: nginx:latestimage: nginx # те саме, що вищеЧому теги важливі
Розділ «Чому теги важливі»# ПОГАНО: latest може змінитися несподіваноimage: nginx:latest
# ДОБРЕ: конкретна версія, відтворюваноimage: nginx:1.21.0
# КРАЩЕ: конкретна версія з базовим образом Alpine (менший)image: nginx:1.21.0-alpineОснови Dockerfile
Розділ «Основи Dockerfile»Dockerfile визначає, як збирати образ. CKAD може попросити вас зрозуміти або модифікувати прості Dockerfile-и.
Мінімальний Dockerfile
Розділ «Мінімальний Dockerfile»# Базовий образFROM python:3.9-slim
# Встановити робочу директоріюWORKDIR /app
# Спочатку скопіювати requirements (кешування шарів)COPY requirements.txt .RUN pip install -r requirements.txt
# Скопіювати код застосункуCOPY . .
# Відкрити порт (документація)EXPOSE 8080
# Команда для запускуCMD ["python", "app.py"]Загальні інструкції
Розділ «Загальні інструкції»| Інструкція | Призначення | Приклад |
|---|---|---|
FROM | Базовий образ | FROM nginx:alpine |
WORKDIR | Встановити робочу директорію | WORKDIR /app |
COPY | Скопіювати файли з контексту збірки | COPY src/ /app/ |
RUN | Виконати команду під час збірки | RUN apt-get update |
ENV | Встановити змінну середовища | ENV PORT=8080 |
EXPOSE | Задокументувати порт (не публікує) | EXPOSE 8080 |
CMD | Команда за замовчуванням для запуску | CMD ["nginx", "-g", "daemon off;"] |
ENTRYPOINT | Основний виконуваний файл | ENTRYPOINT ["python"] |
CMD проти ENTRYPOINT
Розділ «CMD проти ENTRYPOINT»# CMD: Легко перевизначитиFROM nginxCMD ["nginx", "-g", "daemon off;"]# Можна запустити: docker run myimage sleep 10 (замінює CMD)
# ENTRYPOINT: Важко перевизначитиFROM pythonENTRYPOINT ["python"]CMD ["app.py"]# Запускає: python app.py# Можна запустити: docker run myimage script.py (замінює лише CMD)У специфікаціях Підa Kubernetes:
ENTRYPOINTвідповідаєcommand:CMDвідповідаєargs:
spec: containers: - name: app image: python:3.9 command: ["python"] # Перевизначає ENTRYPOINT args: ["myapp.py"] # Перевизначає CMDЗбірка образів
Розділ «Збірка образів»Хоча ви не будете збирати образи в середовищі іспиту (немає Docker-демона), розуміння процесу допомагає налагоджувати проблеми.
Базова збірка
Розділ «Базова збірка»# Збірка в поточній директоріїdocker build -t myapp:v1.0.0 .
# Збірка з конкретним Dockerfiledocker build -t myapp:v1.0.0 -f Dockerfile.prod .
# Збірка з аргументами збіркиdocker build --build-arg VERSION=1.0.0 -t myapp:v1.0.0 .Тегування та завантаження
Розділ «Тегування та завантаження»# Тегувати наявний образdocker tag myapp:v1.0.0 myregistry.com/team/myapp:v1.0.0
# Завантажити до реєструdocker push myregistry.com/team/myapp:v1.0.0
# Завантажити всі тегиdocker push myregistry.com/team/myapp --all-tagsПолітика завантаження образів
Розділ «Політика завантаження образів»Kubernetes вирішує, коли завантажувати образи, на основі imagePullPolicy:
spec: containers: - name: app image: nginx:1.21.0 imagePullPolicy: Always # IfNotPresent | Never | Always| Політика | Поведінка | Використовуйте, коли |
|---|---|---|
Always | Завантажувати щоразу | Використовуєте тег latest, потрібен найсвіжіший образ |
IfNotPresent | Завантажувати лише якщо не закешовано | Конкретні теги, економія трафіку |
Never | Ніколи не завантажувати, використовувати кеш | Локальна розробка, ізольовані мережі |
Поведінка за замовчуванням
Розділ «Поведінка за замовчуванням»| Тег образу | Політика за замовчуванням |
|---|---|
Без тегу (мається на увазі :latest) | Always |
:latest | Always |
Конкретний тег (:v1.0.0) | IfNotPresent |
Дайджест (@sha256:...) | IfNotPresent |
Приватні реєстри
Розділ «Приватні реєстри»Для завантаження з приватних реєстрів потрібна автентифікація:
Крок 1: Створити Secret
Розділ «Крок 1: Створити Secret»# Створити docker-registry secretk create secret docker-registry regcred \ --docker-server=myregistry.com \ --docker-username=user \ --docker-password=password \ --docker-email=user@example.comКрок 2: Посилання у Піді
Розділ «Крок 2: Посилання у Піді»apiVersion: v1kind: Podmetadata: name: private-appspec: containers: - name: app image: myregistry.com/team/myapp:v1.0.0 imagePullSecrets: - name: regcredАльтернатива: ServiceAccount за замовчуванням
Розділ «Альтернатива: ServiceAccount за замовчуванням»apiVersion: v1kind: ServiceAccountmetadata: name: myapp-saimagePullSecrets:- name: regcred---apiVersion: v1kind: Podmetadata: name: private-appspec: serviceAccountName: myapp-sa containers: - name: app image: myregistry.com/team/myapp:v1.0.0Усунення проблем з образами
Розділ «Усунення проблем з образами»Типові помилки
Розділ «Типові помилки»| Помилка | Причина | Рішення |
|---|---|---|
ImagePullBackOff | Неможливо завантажити образ | Перевірте ім’я образу, доступ до реєстру |
ErrImagePull | Завантаження не вдалося | Переконайтеся, що образ існує, перевірте облікові дані |
InvalidImageName | Некоректне посилання на образ | Виправте формат імені образу |
ImageInspectError | Помилка інспекції образу | Перевірте маніфест образу |
Кроки налагодження
Розділ «Кроки налагодження»# Перевірити події Підаk describe pod myapp | grep -A10 Events
# Перевірити ім'я образуk get pod myapp -o jsonpath='{.spec.containers[0].image}'
# Переконатися, що secret існуєk get secret regcred
# Тест завантаження вручну (якщо docker доступний)docker pull myregistry.com/team/myapp:v1.0.0Приклад: Виправлення ImagePullBackOff
Розділ «Приклад: Виправлення ImagePullBackOff»# Під застряг у ImagePullBackOffk get pods# NAME READY STATUS RESTARTS AGE# myapp 0/1 ImagePullBackOff 0 5m
# Перевірити подіїk describe pod myapp# Events:# Failed to pull image "nginx:latst": rpc error: ...not found
# Знайшли: друкарська помилка в тезі (latst замість latest)
# Виправлення: Відредагувати Під або видалити та створити зановоk delete pod myappk run myapp --image=nginx:latestНайкращі практики безпеки образів
Розділ «Найкращі практики безпеки образів»Хоча це не завжди тестується, розуміння цього робить вас кращим розробником:
1. Використовуйте конкретні теги
Розділ «1. Використовуйте конкретні теги»# ПОГАНОimage: nginx:latest
# ДОБРЕimage: nginx:1.21.0-alpine2. Використовуйте мінімальні базові образи
Розділ «2. Використовуйте мінімальні базові образи»# 133MBFROM python:3.9
# 45MB — набагато меншийFROM python:3.9-slim
# 17MB — ще меншийFROM python:3.9-alpine3. Запускайте не від root
Розділ «3. Запускайте не від root»FROM python:3.9-slimRUN useradd -m appuserUSER appuserCOPY --chown=appuser:appuser . /appУ Kubernetes:
spec: securityContext: runAsNonRoot: true runAsUser: 1000 containers: - name: app image: myapp:v1.0.04. Використовуйте файлову систему тільки для читання
Розділ «4. Використовуйте файлову систему тільки для читання»spec: containers: - name: app image: myapp:v1.0.0 securityContext: readOnlyRootFilesystem: true volumeMounts: - name: tmp mountPath: /tmp volumes: - name: tmp emptyDir: {}Чи знали ви?
Розділ «Чи знали ви?»-
Образи контейнерів є шаруватими. Кожна інструкція Dockerfile створює шар. Шари кешуються та спільно використовуються між образами, заощаджуючи дисковий простір та час збірки. Ось чому вміст, що часто змінюється (наприклад,
COPY . .), розміщують в кінці. -
Тег
latest— це лише конвенція. Він насправді не є “найновішим” за часом — це те, що було останнім завантажено без конкретного тегу. Багато проєктів оновлюютьlatestз кожною збіркою, але деякі ніколи його не оновлюють. -
Дайджести образів (sha256:…) є незмінними. Теги можна переміщувати, щоб вони вказували на різні образи, але дайджест завжди посилається на точно той самий вміст образу. Використовуйте дайджести для максимальної відтворюваності у продакшені.
Типові помилки
Розділ «Типові помилки»| Помилка | Чому це шкодить | Рішення |
|---|---|---|
Використання latest у продакшені | Непередбачувані оновлення | Завжди використовуйте конкретні теги |
| Друкарські помилки в іменах образів | ImagePullBackOff | Ретельно перевіряйте написання |
Забули imagePullSecrets | Неможливо завантажити приватні образи | Додайте посилання на secret до Піда |
Неправильна imagePullPolicy | Проблеми з кешем або зайві завантаження | Встановіть явно відповідно до потреб |
| Великі базові образи | Повільне завантаження, поверхня атаки | Використовуйте варіанти -slim або -alpine |
Тест
Розділ «Тест»-
Який тег образу за замовчуванням, якщо жоден не вказано?
Відповідь
`latest`. Наприклад, `nginx` еквівалентно `nginx:latest`. -
Під застряг у ImagePullBackOff. Який перший крок налагодження?
Відповідь
Виконайте `kubectl describe pod <ім'я>` та перевірте секцію Events. Там буде показано конкретну помилку завантаження, наприклад, образ не знайдено або помилка автентифікації. -
Як перевизначити CMD з Dockerfile у специфікації Піда Kubernetes?
Відповідь
Використовуйте поле `args` у специфікації контейнера: ```yaml containers: - name: app image: myimage args: ["new", "command", "here"] ``` -
Яка різниця між
imagePullPolicy: AlwaysтаIfNotPresent?Відповідь
`Always` завантажує образ при кожному запуску Піда, навіть якщо він закешований локально. `IfNotPresent` завантажує лише якщо образу ще немає на вузлі. Використовуйте `Always` для тегів `latest`; використовуйте `IfNotPresent` для конкретних версійних тегів для економії трафіку.
Практична вправа
Розділ «Практична вправа»Завдання: Виправити зламаний Деплоймент з проблемами образів.
Підготовка:
# Створити Деплоймент з навмисними проблемами образуk create deploy broken-app --image=nginx:nonexistentВаші завдання:
- Перевірити, чому Піди не запускаються
- Знайти правильний тег образу
- Виправити Деплоймент
Рішення:
# Перевірити статус Підаk get pods# Показує ImagePullBackOff
# Отримати деталіk describe pod -l app=broken-app | grep -A5 Events# Показує: nginx:nonexistent not found
# Виправити, оновивши Деплойментk set image deploy/broken-app nginx=nginx:1.21.0
# Перевіритиk get pods# Повинен показувати Running
# Очищенняk delete deploy broken-appКритерії успіху:
- Виявлено проблему з образом
- Виправлено посилання на образ
- Під тепер працює
Практичні вправи
Розділ «Практичні вправи»Вправа 1: Аналіз імені образу (Ціль: 2 хвилини)
Розділ «Вправа 1: Аналіз імені образу (Ціль: 2 хвилини)»Визначте компоненти цих посилань на образи:
1. nginx Реєстр: docker.io (за замовчуванням) Простір імен: library (за замовчуванням) Образ: nginx Тег: latest (за замовчуванням)
2. gcr.io/google-containers/pause:3.2 Реєстр: gcr.io Простір імен: google-containers Образ: pause Тег: 3.2
3. mycompany.com/team/app:v2.0.0-alpine Реєстр: mycompany.com Простір імен: team Образ: app Тег: v2.0.0-alpineВправа 2: Виправлення ImagePullBackOff (Ціль: 3 хвилини)
Розділ «Вправа 2: Виправлення ImagePullBackOff (Ціль: 3 хвилини)»# Створити зламаний Підk run broken --image=nginx:1.999.0
# Діагностикаk describe pod broken | grep -A5 Events
# Виправленняk delete pod brokenk run broken --image=nginx:1.21.0
# Перевіркаk get pod broken
# Очищенняk delete pod brokenВправа 3: Secret для приватного реєстру (Ціль: 4 хвилини)
Розділ «Вправа 3: Secret для приватного реєстру (Ціль: 4 хвилини)»# Створити secret реєструk create secret docker-registry myregistry \ --docker-server=private.registry.io \ --docker-username=testuser \ --docker-password=testpass
# Створити Під з посиланням на secretcat << EOF | k apply -f -apiVersion: v1kind: Podmetadata: name: private-podspec: containers: - name: app image: private.registry.io/app:latest imagePullSecrets: - name: myregistryEOF
# Перевірити, чи secret прив'язаноk get pod private-pod -o jsonpath='{.spec.imagePullSecrets}'
# Очищенняk delete pod private-podk delete secret myregistryВправа 4: Перевизначення Command та Args (Ціль: 3 хвилини)
Розділ «Вправа 4: Перевизначення Command та Args (Ціль: 3 хвилини)»# Створити Під, що перевизначає CMDcat << EOF | k apply -f -apiVersion: v1kind: Podmetadata: name: custom-cmdspec: containers: - name: busybox image: busybox command: ["sh", "-c"] args: ["echo 'Custom command' && sleep 10"]EOF
# Перевірити логиk logs custom-cmd
# Перевірити командуk get pod custom-cmd -o jsonpath='{.spec.containers[0].command}'k get pod custom-cmd -o jsonpath='{.spec.containers[0].args}'
# Очищенняk delete pod custom-cmdВправа 5: Тестування imagePullPolicy (Ціль: 3 хвилини)
Розділ «Вправа 5: Тестування imagePullPolicy (Ціль: 3 хвилини)»# Створити Піди з різними політикамиcat << EOF | k apply -f -apiVersion: v1kind: Podmetadata: name: pull-alwaysspec: containers: - name: nginx image: nginx:1.21.0 imagePullPolicy: Always---apiVersion: v1kind: Podmetadata: name: pull-ifnotpresentspec: containers: - name: nginx image: nginx:1.21.0 imagePullPolicy: IfNotPresentEOF
# Перевірити політикиk get pod pull-always -o jsonpath='{.spec.containers[0].imagePullPolicy}'k get pod pull-ifnotpresent -o jsonpath='{.spec.containers[0].imagePullPolicy}'
# Очищенняk delete pod pull-always pull-ifnotpresentВправа 6: Повне усунення проблем з образами (Ціль: 5 хвилин)
Розділ «Вправа 6: Повне усунення проблем з образами (Ціль: 5 хвилин)»Сценарій: Колега створив Деплоймент, але Піди не запускаються.
# Підготовка (симуляція проблеми)k create deploy webapp --image=nginx:alpine-wrong-tag
# ВАШЕ ЗАВДАННЯ: Знайти та виправити проблему
# Крок 1: Перевірити статус Деплойментаk get deploy webappk get pods -l app=webapp
# Крок 2: Дослідити помилкуk describe pods -l app=webapp | grep -A10 Events
# Крок 3: Знайти правильний тег образу# (У реальному сценарії перевірте реєстр або документацію)# Правильний тег — nginx:alpine
# Крок 4: Виправитиk set image deploy/webapp nginx=nginx:alpine
# Крок 5: Перевіритиk rollout status deploy/webappk get pods -l app=webapp
# Очищенняk delete deploy webappНаступний модуль
Розділ «Наступний модуль»Модуль 1.2: Jobs та CronJobs — Запуск одноразових та запланованих пакетних завдань.