Команда Docker не найдена на Mac: Устранение неполадок и настройка среды

DockerBeginner
Практиковаться сейчас

Введение

Docker произвел революцию в разработке приложений, позволяя разработчикам создавать, развертывать и запускать приложения в изолированных средах, называемых контейнерами (containers). Пользователи Mac иногда сталкиваются с ошибкой "docker command not found" (команда docker не найдена), что может вызывать разочарование при начале работы с контейнеризацией. Эта лабораторная работа (lab) проведет вас через понимание концепций Docker, проверку вашей установки Docker, устранение распространенных проблем и настройку правильной среды Docker для вашей работы по разработке.

Понимание основ Docker и проверка установки

Docker предоставляет стандартизированный способ упаковки приложений и их зависимостей в контейнеры (containers), делая их переносимыми между различными средами. Прежде чем приступить к устранению каких-либо проблем с Docker, давайте убедимся, что мы понимаем основы и проверим нашу установку.

Что такое Docker?

Docker - это платформа, которая использует технологию контейнеризации, чтобы упростить создание, развертывание и запуск приложений. В отличие от виртуальных машин, контейнеры Docker совместно используют ядро хост-системы, но работают в изолированных средах, что делает их легковесными и эффективными.

Ключевые компоненты Docker включают в себя:

  • Docker Engine: Среда выполнения, которая собирает и запускает контейнеры
  • Docker Images: Шаблоны только для чтения, используемые для создания контейнеров
  • Docker Containers: Запущенные экземпляры образов Docker
  • Docker Registry: Репозиторий для хранения и обмена образами Docker
  • Dockerfile: Текстовый файл, содержащий инструкции по сборке образа Docker

Проверка установки Docker

В нашей лабораторной среде (lab environment) Docker уже установлен. Давайте проверим это, проверив версию Docker:

docker --version

Вы должны увидеть вывод, похожий на:

Docker version 20.10.21, build 20.10.21-0ubuntu1~22.04.3

Теперь давайте проверим, запущен ли демон Docker:

sudo systemctl status docker

Вы должны увидеть вывод, указывающий на то, что Docker активен (запущен). Вывод будет выглядеть примерно так:

● docker.service - Docker Application Container Engine
     Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
     Active: active (running) since ...

Нажмите q, чтобы выйти из просмотра статуса.

Если по какой-либо причине Docker не запущен, вы можете запустить его с помощью:

sudo systemctl start docker

Запуск вашего первого контейнера

Давайте убедимся, что Docker работает правильно, запустив простой контейнер "hello-world":

docker run hello-world

Эта команда загружает образ hello-world, если он еще не доступен локально, и запускает его в контейнере. Вы должны увидеть вывод, похожий на:

Hello from Docker!
This message shows that your installation appears to be working correctly.
...

Вывод объясняет, что Docker сделал для запуска этого контейнера, предоставляя хорошее введение в то, как работает Docker.

Проверка запущенных контейнеров

Чтобы увидеть все текущие запущенные контейнеры, используйте:

docker ps

Поскольку контейнер hello-world завершает работу сразу после отображения своего сообщения, вы, вероятно, не увидите его в этом списке. Чтобы увидеть все контейнеры, включая те, которые были остановлены, используйте:

docker ps -a

Это показывает все контейнеры, их идентификаторы, образы, из которых они были созданы, когда они были созданы и их текущий статус.

Теперь вы убедились, что Docker установлен и работает правильно в вашей среде, и вы запустили свой первый контейнер!

Работа с образами и контейнерами Docker

Теперь, когда вы убедились, что Docker работает правильно, давайте узнаем, как работать с образами и контейнерами Docker более подробно.

Понимание образов Docker

Образы Docker - это чертежи для контейнеров. Они содержат код приложения, библиотеки, зависимости, инструменты и другие файлы, необходимые для запуска приложения.

Давайте рассмотрим образы Docker, используя некоторые основные команды:

Вывод списка доступных образов

Чтобы увидеть все образы Docker, доступные в вашей системе:

docker images

Вы должны увидеть вывод, похожий на:

REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
hello-world   latest    feb5d9fea6a5   X months ago    13.3kB

Загрузка образов из Docker Hub

Docker Hub - это облачный реестр, где вы можете найти и поделиться образами Docker. Давайте загрузим популярный образ:

docker pull nginx

Эта команда загружает последний образ веб-сервера nginx. Вы увидите вывод о ходе загрузки различных слоев образа:

Using default tag: latest
latest: Pulling from library/nginx
...
Digest: sha256:...
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest

Запустите docker images еще раз, чтобы увидеть недавно загруженный образ nginx в вашем списке.

Работа с контейнерами

Теперь, когда у нас есть некоторые образы, давайте узнаем, как создавать контейнеры и управлять ими.

Запуск контейнера

Давайте запустим контейнер nginx, который будет обслуживать веб-страницу:

docker run --name my-nginx -p 8080:80 -d nginx

Эта команда выполняет несколько действий:

  • --name my-nginx: Называет контейнер "my-nginx"
  • -p 8080:80: Отображает порт 8080 на вашем хосте на порт 80 в контейнере
  • -d: Запускает контейнер в detached mode (в фоновом режиме)
  • nginx: Указывает образ для использования

Проверка работы контейнера

Проверьте, что ваш контейнер запущен:

docker ps

Вы должны увидеть свой контейнер nginx в списке запущенных контейнеров:

CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS                  NAMES
a1b2c3d4e5f6   nginx     "/docker-entrypoint.…"   X seconds ago    Up X seconds    0.0.0.0:8080->80/tcp   my-nginx

Доступ к веб-серверу

Вы можете получить доступ к веб-серверу nginx, открыв веб-браузер в вашей среде LabEx VM и перейдя по адресу:

http://localhost:8080

Альтернативно, вы можете использовать curl из терминала:

curl http://localhost:8080

Вы должны увидеть HTML-страницу приветствия nginx по умолчанию.

Просмотр журналов контейнера

Чтобы увидеть журналы для вашего контейнера:

docker logs my-nginx

Это показывает журналы доступа для сервера nginx.

Остановка и удаление контейнеров

Чтобы остановить запущенный контейнер:

docker stop my-nginx

Чтобы удалить контейнер (он должен быть сначала остановлен):

docker rm my-nginx

Убедитесь, что контейнер был удален:

docker ps -a

Контейнер с именем "my-nginx" больше не должен отображаться в списке.

Теперь вы понимаете основы работы с образами и контейнерами Docker. Вы загрузили образы из Docker Hub, запустили контейнеры, отобразили порты, просмотрели журналы и управляли жизненными циклами контейнеров.

Создание собственных образов Docker с помощью Dockerfile

До сих пор мы использовали готовые образы Docker из Docker Hub. Теперь давайте узнаем, как создавать собственные пользовательские образы Docker с помощью Dockerfile.

Что такое Dockerfile?

Dockerfile - это текстовый файл, содержащий инструкции по сборке образа Docker. Он указывает базовый образ, добавляет файлы, устанавливает программное обеспечение, устанавливает переменные среды и настраивает контейнер, который будет создан из образа.

Создание вашего первого Dockerfile

Давайте создадим простое веб-приложение с использованием Node.js и упакуем его как образ Docker.

Сначала создайте новый каталог для вашего проекта:

mkdir -p ~/project/node-app
cd ~/project/node-app

Теперь создайте простое приложение Node.js. Сначала создайте файл с именем app.js:

nano app.js

Добавьте следующий код в файл:

const http = require("http");

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader("Content-Type", "text/plain");
  res.end("Hello World from Docker!\n");
});

const port = 3000;
server.listen(port, () => {
  console.log(`Server running at http://localhost:${port}/`);
});

Сохраните файл, нажав Ctrl+O, затем Enter, и выйдите из nano с помощью Ctrl+X.

Далее создайте файл package.json, чтобы определить ваше приложение Node.js:

nano package.json

Добавьте следующее содержимое:

{
  "name": "docker-node-app",
  "version": "1.0.0",
  "description": "A simple Node.js app for Docker",
  "main": "app.js",
  "scripts": {
    "start": "node app.js"
  },
  "author": "",
  "license": "ISC"
}

Сохраните и выйдите из nano.

Теперь создайте Dockerfile:

nano Dockerfile

Добавьте следующее содержимое:

## Use an official Node.js runtime as the base image
FROM node:14-alpine

## Set the working directory in the container
WORKDIR /usr/src/app

## Copy package.json and package-lock.json
COPY package.json ./

## Install dependencies
RUN npm install

## Copy the application code
COPY app.js ./

## Expose the port the app runs on
EXPOSE 3000

## Command to run the application
CMD ["npm", "start"]

Сохраните и выйдите из nano.

Сборка вашего образа Docker

Теперь, когда у вас есть Dockerfile, вы можете собрать свой образ Docker:

docker build -t my-node-app .

Эта команда собирает образ из вашего Dockerfile:

  • -t my-node-app: Тегирует образ именем "my-node-app"
  • .: Указывает, что Dockerfile находится в текущем каталоге

Вы увидите вывод, показывающий ход сборки:

Sending build context to Docker daemon  X.XXkB
Step 1/7 : FROM node:14-alpine
 ---> XXXXXXXXXX
Step 2/7 : WORKDIR /usr/src/app
 ---> XXXXXXXXXX
...
Successfully built XXXXXXXXXX
Successfully tagged my-node-app:latest

Запуск вашего пользовательского образа Docker

Теперь запустите контейнер, используя ваш недавно собранный образ:

docker run --name node-app-container -p 3000:3000 -d my-node-app

Убедитесь, что контейнер запущен:

docker ps

Вы должны увидеть свой контейнер в списке:

CONTAINER ID   IMAGE         COMMAND         CREATED          STATUS          PORTS                    NAMES
XXXXXXXXXX     my-node-app   "npm start"     X seconds ago    Up X seconds    0.0.0.0:3000->3000/tcp   node-app-container

Тестирование вашего приложения

Протестируйте приложение, сделав HTTP-запрос к нему:

curl http://localhost:3000

Вы должны увидеть:

Hello World from Docker!

Понимание Dockerfile

Давайте рассмотрим ключевые компоненты нашего Dockerfile:

  1. FROM node:14-alpine: Указывает базовый образ для использования
  2. WORKDIR /usr/src/app: Устанавливает рабочий каталог внутри контейнера
  3. COPY package.json ./: Копирует файлы с хоста в контейнер
  4. RUN npm install: Выполняет команду внутри контейнера во время процесса сборки
  5. EXPOSE 3000: Документирует, что контейнер прослушивает порт 3000
  6. CMD ["npm", "start"]: Указывает команду для запуска при запуске контейнера

Очистка

Давайте очистим, остановив и удалив контейнер:

docker stop node-app-container
docker rm node-app-container

Теперь вы узнали, как создавать свои собственные образы Docker с помощью Dockerfile, собирать эти образы и запускать контейнеры на их основе. Это фундаментальный навык для разработки Docker.

Управление данными с помощью томов Docker

Одной из проблем при работе с контейнерами Docker является сохранение данных. Контейнеры эфемерны, что означает, что любые данные, созданные внутри контейнера, теряются при удалении контейнера. Тома Docker решают эту проблему, предоставляя способ сохранения данных за пределами контейнеров.

Понимание томов Docker

Тома Docker - это предпочтительный механизм для сохранения данных, созданных и используемых контейнерами Docker. Они полностью управляются Docker и изолированы от структуры каталогов файловой системы хоста.

Преимущества использования томов включают:

  • Тома легче резервировать или переносить, чем привязки (bind mounts)
  • Вы можете управлять томами с помощью команд CLI Docker
  • Тома работают как в контейнерах Linux, так и в контейнерах Windows
  • Тома можно безопаснее совместно использовать между несколькими контейнерами
  • Драйверы томов позволяют хранить тома на удаленных хостах, у поставщиков облачных услуг или шифровать содержимое томов

Создание и использование томов Docker

Давайте создадим простой контейнер базы данных MySQL, который использует том для сохранения своих данных.

Создание тома

Сначала создайте том Docker:

docker volume create mysql-data

Вы можете вывести список всех томов с помощью:

docker volume ls

Вы должны увидеть свой новый том в списке:

DRIVER    VOLUME NAME
local     mysql-data

Запуск контейнера с томом

Теперь давайте запустим контейнер MySQL, который использует этот том:

docker run --name mysql-db -e MYSQL_ROOT_PASSWORD=mysecretpassword -v mysql-data:/var/lib/mysql -p 3306:3306 -d mysql:5.7

Эта команда:

  • --name mysql-db: Называет контейнер "mysql-db"
  • -e MYSQL_ROOT_PASSWORD=mysecretpassword: Устанавливает переменную среды для настройки MySQL
  • -v mysql-data:/var/lib/mysql: Подключает том "mysql-data" к каталогу, в котором MySQL хранит свои данные
  • -p 3306:3306: Отображает порт 3306 на хосте на порт 3306 в контейнере
  • -d: Запускает контейнер в detached mode (в фоновом режиме)
  • mysql:5.7: Указывает образ для использования

Подождите немного, пока контейнер запустится, затем проверьте, что он работает:

docker ps

Взаимодействие с базой данных

Давайте создадим базу данных и таблицу, чтобы продемонстрировать сохранение данных. Сначала подключитесь к контейнеру MySQL:

docker exec -it mysql-db bash

Внутри контейнера подключитесь к серверу MySQL:

mysql -u root -pmysecretpassword

Создайте новую базу данных и таблицу:

CREATE DATABASE testdb;
USE testdb;
CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255));
INSERT INTO users (name) VALUES ('John'), ('Jane'), ('Bob');
SELECT * FROM users;

Вы должны увидеть вставленные данные:

+----+------+
| id | name |
+----+------+
|  1 | John |
|  2 | Jane |
|  3 | Bob  |
+----+------+

Выйдите из приглашения MySQL и контейнера:

exit
exit

Тестирование сохранения тома

Теперь давайте остановим и удалим контейнер, а затем создадим новый, используя тот же том:

docker stop mysql-db
docker rm mysql-db

Создайте новый контейнер, используя тот же том:

docker run --name mysql-db-new -e MYSQL_ROOT_PASSWORD=mysecretpassword -v mysql-data:/var/lib/mysql -p 3306:3306 -d mysql:5.7

Теперь подключитесь к новому контейнеру и проверьте, сохранились ли наши данные:

docker exec -it mysql-db-new bash
mysql -u root -pmysecretpassword
USE testdb
SELECT * FROM users

Вы должны увидеть те же данные, которые мы вставили ранее:

+----+------+
| id | name |
+----+------+
|  1 | John |
|  2 | Jane |
|  3 | Bob  |
+----+------+

Выйдите из приглашения MySQL и контейнера:

exit
exit

Это демонстрирует, что данные сохранились даже после удаления исходного контейнера, потому что они были сохранены в томе Docker.

Проверка и управление томами

Вы можете проверить том, чтобы получить больше информации о нем:

docker volume inspect mysql-data

Это покажет такие детали, как точка монтирования и используемый драйвер:

[
  {
    "CreatedAt": "YYYY-MM-DDTHH:MM:SS+00:00",
    "Driver": "local",
    "Labels": {},
    "Mountpoint": "/var/lib/docker/volumes/mysql-data/_data",
    "Name": "mysql-data",
    "Options": {},
    "Scope": "local"
  }
]

Чтобы очистить, давайте остановим и удалим контейнер:

docker stop mysql-db-new
docker rm mysql-db-new

Если вы хотите удалить и том:

docker volume rm mysql-data

Теперь вы узнали, как использовать тома Docker для сохранения данных между жизненными циклами контейнеров, что необходимо для stateful applications (приложений с сохранением состояния), таких как базы данных.

Изучение сети Docker

Сеть Docker позволяет контейнерам взаимодействовать друг с другом и с внешним миром. Понимание сетевых возможностей Docker имеет решающее значение для создания многоконтейнерных приложений.

Типы сетей Docker

Docker предоставляет несколько сетевых драйверов из коробки:

  • bridge (мост): Сетевой драйвер по умолчанию. Контейнеры в одной сети bridge могут взаимодействовать.
  • host (хост): Удаляет сетевую изоляцию между контейнером и хостом.
  • none (нет): Отключает все сетевые подключения для контейнера.
  • overlay (наложение): Подключает несколько демонов Docker и позволяет службам Swarm взаимодействовать.
  • macvlan: Назначает MAC-адрес контейнеру, делая его похожим на физическое устройство в сети.

Изучение сети bridge по умолчанию

При установке Docker он автоматически создает сеть bridge по умолчанию. Давайте изучим ее:

docker network ls

Вы должны увидеть вывод, похожий на:

NETWORK ID     NAME      DRIVER    SCOPE
XXXXXXXXXXXX   bridge    bridge    local
XXXXXXXXXXXX   host      host      local
XXXXXXXXXXXX   none      null      local

Вы можете проверить сеть bridge по умолчанию:

docker network inspect bridge

Эта команда предоставляет подробную информацию о сети, включая контейнеры, подключенные к ней, диапазон IP-адресов и шлюз.

Создание и использование пользовательских сетей bridge

Давайте создадим пользовательскую сеть bridge для лучшей изоляции контейнеров:

docker network create my-network

Убедитесь, что сеть была создана:

docker network ls

Вы должны увидеть свою новую сеть в списке:

NETWORK ID     NAME           DRIVER    SCOPE
XXXXXXXXXXXX   bridge         bridge    local
XXXXXXXXXXXX   host           host      local
XXXXXXXXXXXX   my-network     bridge    local
XXXXXXXXXXXX   none           null      local

Теперь давайте запустим два контейнера в этой сети и продемонстрируем взаимодействие между ними.

Сначала запустите контейнер NGINX в пользовательской сети:

docker run --name web-server --network my-network -d nginx

Далее давайте запустим контейнер Alpine Linux и используем его для проверки подключения к контейнеру NGINX:

docker run --name alpine --network my-network -it alpine sh

Внутри контейнера Alpine установите curl и проверьте подключение к контейнеру NGINX:

apk add --update curl
curl web-server

Вывод должен быть HTML-кодом приветственной страницы NGINX. Это работает, потому что Docker предоставляет встроенный DNS для контейнеров в пользовательских сетях, позволяя им преобразовывать имена контейнеров в IP-адреса.

Введите exit, чтобы выйти из контейнера Alpine:

exit

Подключение контейнеров к нескольким сетям

Контейнеры могут быть подключены к нескольким сетям. Давайте создадим еще одну сеть:

docker network create another-network

Подключите существующий контейнер web-server к этой новой сети:

docker network connect another-network web-server

Убедитесь, что контейнер теперь подключен к обеим сетям:

docker inspect web-server -f '{{json .NetworkSettings.Networks}}' | json_pp

Вы должны увидеть, что контейнер подключен как к my-network, так и к another-network.

Запуск контейнеров с публикацией портов

Когда вы хотите сделать службу контейнера доступной извне хоста Docker, вам необходимо опубликовать его порты:

docker run --name public-web -p 8080:80 -d nginx

Эта команда сопоставляет порт 8080 на хосте с портом 80 в контейнере. Вы можете получить доступ к веб-серверу NGINX, используя:

curl http://localhost:8080

Вы должны увидеть приветственную страницу NGINX.

Очистка

Давайте очистим созданные нами контейнеры и сети:

docker stop web-server alpine public-web
docker rm web-server alpine public-web
docker network rm my-network another-network

Убедитесь, что контейнеры и сети были удалены:

docker ps -a
docker network ls

Понимание взаимодействия контейнеров

Этот шаг продемонстрировал, как сеть Docker позволяет:

  1. Взаимодействие между контейнерами с использованием пользовательских сетей
  2. Разрешение DNS с использованием имен контейнеров
  3. Подключение контейнеров к нескольким сетям
  4. Предоставление служб контейнеров внешнему миру с использованием публикации портов

Эти сетевые возможности необходимы для создания сложных многоконтейнерных приложений, в которых компоненты должны взаимодействовать друг с другом и с внешними службами.

Заключение

Поздравляем с завершением этой лабораторной работы по Docker! Вы изучили основные концепции и навыки Docker, которые составляют основу разработки и развертывания на основе контейнеров.

В этой лабораторной работе вы:

  • Проверили установку Docker и запустили свой первый контейнер
  • Работали с образами и контейнерами Docker, включая извлечение образов из Docker Hub и управление жизненными циклами контейнеров
  • Создали свой собственный пользовательский образ Docker с использованием Dockerfile
  • Использовали тома Docker для сохранения данных между жизненными циклами контейнеров
  • Изучили сети Docker для обеспечения взаимодействия между контейнерами

Эти навыки позволят вам:

  • Упаковывать приложения и их зависимости в переносимые контейнеры
  • Создавать стандартизированные среды для разработки, тестирования и производства
  • Реализовывать архитектуры микросервисов, где каждый компонент работает в своем собственном контейнере
  • Обеспечивать сохранность данных для приложений с сохранением состояния
  • Создавать сложные многоконтейнерные приложения с надлежащей изоляцией и связью

Docker стал важным инструментом в современной разработке программного обеспечения, и полученные вами знания будут ценны в широком спектре сценариев разработки и эксплуатации.