Практическое руководство по Docker, написанное для внешнего интерфейса

Docker

Полный текст — более 10 000 слов, после прочтения этой статьи вам может понадобиться чашечка кофе☕️~

авторАрахис ПЭА, пользователь интерфейса Baidu Ван, ACGer. Личный блог pea3nut.blog Профиль pea3nut.info

Если вы сохраните этот абзац, не стесняйтесь перепечатывать его. Пожалуйста, убедитесь, что этот абзац находится в верхней части статьи.

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

  • Основные понятия докера
  • Реальный процесс миграции сайта:
    • статический сайт
    • Сайт Nodejs (Экспресс)
    • WordPress(PHP)
  • Некоторые необходимые навыки: запуск, общая оболочка

В статье будут описаны все технологические стеки (Github CI, обратный прокси Nginx, docker-compose), используемые в процессе использования Docker, и никогда не будет «см.:http://xxx" кидаю ссылки

Не нужно сверяться с другими документами, просто прочитайте один!

good

Какие текущие проблемы

Ручное развертывание слишком дорого

Автор поддерживает ряд веб-сайтов, в том числе:

  • мое резюме:pea3nut.info, одностраничное приложение SPA, созданное с помощью Vuejs, чисто статическое
  • мой блог:pea3nut.blog, используя известную сборку WordPress (PHP+Apache+MySQL)
  • Проект с открытым исходным кодом - Pxer:pxer.pea3nut.org, официальный сайт построен на Nodejs + Express SSR

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

  • Скачать: Загрузите код с Github, затем локальноnpm install
  • Разработка:npm run devИзмените код локально, протестируйте
  • Скомпилировать:npm run buildСкомпилируйте с помощью Webpack для создания статических ресурсов
  • Загрузить: Откройте программное обеспечение FTP и загрузите файл замены.
  • Тест: посмотрите, нормально ли сайт работает в Интернете.
  • commit: зафиксировать код на Github

Даже если я просто исправлю опечатку, это займет десять минут

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

Служба не работает, я не понимаю Linux и не могу устранить неполадки

Недавно я обнаружил, что мой процесс MySQL всегда зависает, что приводит к зависанию всех сайтов, зависящих от MySQL.

не знаю почему, раньше было нормально

why

Я попытался перезапустить процесс, перезапустить сервер и получить журнал ошибок Baidu, но это не сработало.

Ну, на самом деле я мало что знаю о Linux или MySQL, я просто хочу использовать их для создания сайта на WordPress. И в последнее время всегда были проблемы, которые заставили меня осознать:

Я не только должен поддерживать сайт, я также должен поддерживать окружающую среду.

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

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

i-am-so-hard

Перезагрузка не работает. . . Тогда просто переустановите систему

Однако из-за построения множества площадок среда VPS-сервера довольно сложная (возможно, именно поэтому MySQL зависает), а в конфигурационном файле Apache всего сотни строк. Стоимость миграции, связанная с переделкой системы, одна только мысль об этом требует всего моего мужества.

Новое техническое решение - Докер

Резюмируя следующие вопросы:

  • Стоимость ручного развертывания слишком высока, а исправлять опечатки очень хлопотно.
  • Сервер имеет «грязную» среду из-за накопления времени
  • Стоимость переустановки системы слишком высока, а мигрировать сложно

И Докер, это я все решаюSCP-500 Панацея!

Так как же Docker это делает?

Образы и контейнеры

В Docker есть две важные концепции.

Одним из них является контейнер: контейнер особенно похож на виртуальную машину, и в контейнере работает полная операционная система. Nodejs можно установить в контейнер и запуститьnpm install, может делать все, что может ваша текущая операционная система

Другой — образ: образ — это файл, который используется для создания контейнера. Если вы установили операционную систему Windows, то образ Docker особенно похож на файл «Win7 pure version .rar».

Это все, что вам нужно знать об основах Docker. Это так просто

Кстати, в Docker мы обычно называем реальную ОС, которую вы сейчас используете, «Хост».

Установить Докер

Установить Docker на свой компьютер так же просто, как установить VS Code

Если вы используете компьютер с Windows, вам необходимо приобрести версию, поддерживающую виртуализацию. Например, Win10 Professional Edition, Win10 Home Edition неприемлема.

После установки Docker вы можете открыть красивое окно Docker. На самом деле это окно бесполезно, обычно мы управляем Docker через командную строку CLI, так же как и Git

запустить докер

Затем мы создаем сервер Nginx, на котором могут размещаться статические файлы.

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

Образ упакован через Dockerfile, который очень похож на наш внешний интерфейс.package.jsonдокумент

Итак, создайте отношения как:

Dockerfile: 类似于“package.json”
 |
 V
Image: 类似于“Win7纯净版.rar”
 |
 V
Container: 一个完整操作系统

Создать файл

мы создаем каталогhello-docker, в каталоге, чтобы создатьindex.htmlфайл, содержание:

<h1>Hello docker</h1>

Затем создайте новый в каталогеDockerfileфайл, содержание:

FROM nginx

COPY ./index.html /usr/share/nginx/html/index.html

EXPOSE 80

На этом этапе ваша файловая структура должна быть:

hello-docker
  |____index.html
  |____Dockerfile

образ пакета

Файл создан, теперь мы можемDockerfileСоздайте образ!

В командной строке (Windows предпочитает PowerShell) введите:

cd hello-docker/ # 进入刚刚的目录
docker image build ./ -t hello-docker:1.0.0 # 打包镜像

Уведомление! Docker 中的选项(Options)放的位置非常有讲究,docker —help imageа такжеdocker image —helpэто совсем другая команда

docker image build ./ -t hello-docker:1.0.0означает: на основе пути./(текущий путь) упаковать образ, имя образаhello-docker, номер версии1.0.0. Команда автоматически найдетDockerfileупаковать изображение

Советы: вы можете использоватьdocker imagesдля просмотра существующих зеркал на этой машине

Неудивительно, что вы должны получить следующий результат:

Sending build context to Docker daemon  3.072kB
Step 1/3 : FROM nginx
 ---> 5a3221f0137b
Step 2/3 : COPY ./index.html /usr/share/nginx/html/index.html
 ---> 1c433edd5891
Step 3/3 : EXPOSE 80
 ---> Running in c2ff9ec2e945
Removing intermediate container c2ff9ec2e945
 ---> f6a472c1b0a0
Successfully built f6a472c1b0a0
Successfully tagged hello-docker:1.0.0

Вы можете видеть, что он запускает содержимое в Dockerfile, теперь мы просто его дизассемблируем:

  • FROM nginx: В зависимости от того, какое зеркало
  • COPY ./index.html /usr/share/nginx/html/index.html: поместить хост в./index.htmlфайл копируется в контейнер/usr/share/nginx/html/index.html
  • EXPOSE 80: Контейнер открывает порт 80 для внешнего мира.

запустить контейнер

Мы только что создали образ с помощью Dockerfile. Теперь, когда у нас есть образ, нам нужно создать контейнер на его основе:

docker container create -p 2333:80 hello-docker:1.0.0
docker container start xxx # xxx 为上一条命令运行得到的结果

затем откройте в браузере127.0.0.1:2333, вы должны сами увидеть, что вы только что написалиindex.htmlсодержание

В первой команде выше мы используемdocker container createДля создания основыhello-docker:1.0.0Контейнер изображения, используя-pуказать привязку к порту - поставить80Порт привязан к хосту2333порт. После выполнения команды будет возвращен идентификатор контейнера.

Вторая команда — запустить контейнер

После запуска вы можете получить доступ к2333порт для доступа внутрь контейнера80Эффект порта

Советы: вы можете использоватьdocker container lsдля просмотра запущенных в данный момент контейнеров

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

docker container exec -it xxx /bin/bash # xxx 为容器ID

Принцип собственно в том, чтобы запустить контейнер/bin/bash, то можно пройтиbash shellвзаимодействует с контейнером. как будто удаленно подключен к SSH

что случилось

Подытожим, что произошло:

  1. Написать Dockerfile
  2. использоватьdocker image buildбудущееDockerfileупаковано как изображение
  3. использоватьdocker container createсоздать контейнер из образа
  4. использоватьdocker container startзапустить созданный контейнер

docker-works

Хотя это очень просто, разве вы не чувствуете, что «мир огромен, есть много дел, и вы можете делать все, что хотите»?

Перенос статического сайта

Далее мы фактически перенесем чистый статический одностраничный сайт SPA, написанный на Vuejs:

что я собираюсь делать

Перед миграцией Docker, если я хочу обновить содержимое онлайн-сайта, мне необходимо:

  1. местныйnpm run buildУпаковка и вывод статических файлов
  2. Вручную загрузить на сервер через FTP
  3. git pushОбновите исходный код Github

Немного проблем, поэтому я планирую изменить это:

  1. воплощать в жизньgit push
  2. Автоматически определять наличие обновлений кода на github и автоматически упаковывать образ Docker.
  3. После компиляции CI подключитесь к VPS по SSH, удалите существующий контейнер и создайте новый контейнер с новым образом.

И польза от этого:

  1. Больше никаких ручных FTP-загрузок
  2. Когда я выполняю простые операции, такие как исправление опечаток, я могу быть освобожден от тестирования. сразу после сменыgit push, вместо того, чтобы быть локальнымnpm run build

КИ в Github

Во-первых, заставить Github упаковывать образ каждый раз, когда я обновляю код.

На Github доступны бесплатные ресурсы CI, этоTravis CI

Добавить в корневой каталог проекта.travis.ymlфайл со следующим содержимым:

language: node_js
node_js:
  - "12"
services:
  - docker

before_install:
  - npm install

script:
  - npm run build
  - echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
  - docker build -t pea3nut/pea3nut-info:latest .
  - docker push pea3nut/pea3nut-info:latest

Содержимое файла очень простое, просто используйтеnpm run buildПосле компиляции статического вывода упакуйте и передайте зеркало на удаленный сервер. Есть несколько вещей, о которых стоит поговорить подробно:

  • Чтобы иметь возможность загрузить изображение на сервер, вам необходимоhub.docker.comЗарегистрируйте учетную запись в , затем замените код вpea3nut/pea3nut-info:latestдля用户名/包名:latestТолько что
  • После использования Github для входа в Travis CI нажмите знак + плюс слева, чтобы добавить собственный репозиторий Github, вам нужно перейти к настройке, чтобы добавить его в проект.DOCKER_USERNAMEа такжеDOCKER_PASSWORDпеременные окружения. Это гарантирует, что мы можем войти в систему тайно, не будучи другими пользователями Docker Hub, чтобы увидеть ваш пароль. Как показано ниже

add-a-now-project-in-travis-ci

Затем вам нужно добавить Dockerfile, чтобы описать, как упаковать образ Docker.

согласно с.travis.ymlПоследовательность команд при упаковке образаnpm run buildОн был реализован, и результаты проекта уже доступны. Не нужно запускать в контейнере Dockernpm installа такжеnpm run buildИ так далее, просто скопируйте файл напрямую:

FROM nginx

COPY ./dist/ /usr/share/nginx/html/

EXPOSE 80

Примечание: несмотря на простоту процесса, очереди очень длинные, поэтому рекомендуется выполнять несколько тестов локально.git push

Если ваш скомпилированный статический сайт также является одностраничным приложением SPA, вам необходимо добавить дополнительную конфигурацию Nginx, чтобы обеспечить доступность запросов.index.html. Ниже то, что я написалvhost.nginx.confФайл конфигурации Nginx, перенаправляйте все запросы, которые не обращаются к файлам, на/index.html:

server {
    listen 80;
    server_name localhost;
    location / {
        root /usr/share/nginx/html;
        index index.html index.htm;
        proxy_set_header Host $host;

        if (!-f $request_filename) {
          rewrite ^.*$ /index.html break;
        }

    }

    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;
    }
}

Затем добавьте новую строку в Dockerfile, чтобы добавитьvhost.nginx.confДокумент копирования в контейнер/etc/nginx/conf.d/pea3nut-info.confПусть nginx способна прочитать файл конфигурации:

  FROM nginx

  COPY ./dist/ /usr/share/nginx/html/
+ COPY ./vhost.nginx.conf /etc/nginx/conf.d/pea3nut-info.conf

  EXPOSE 80

затем выполнитьgit pushПосле этого вы можете увидеть результат компиляции CI в Travis CI. Если с компиляцией все в порядке, на пульте действительно естьpea3nut/pea3nut-info:latestэто зеркало. Вы можете попробовать это локально, чтобы увидеть, нормально ли работает зеркало:

docker image pull pea3nut/pea3nut-info:latest
docker container create -p 8082:80 pea3nut/pea3nut-info:latest
docker container start xxx # xxx 为上一条命令执行的返回值

После завершения операции браузер получает доступ127.0.0.1:8082Вы должны увидеть эффект!

Затем вы можете войти на удаленный сервер VPS, установить Docker и выполнить ту же команду. Затем получите доступ к общедоступному IP + номеру порта 8082 удаленного сервера VPS, вы должны увидеть тот же эффект, что и локальный.

Советы: Забыли, как установить Docker на VPS? В разделе «Установка Docker» выше вам может понадобиться установка Linux

curl https://get.docker.com/ > install-docker.sh # 下载安装脚本
sh install-docker.sh # 执行安装脚本

Обратный прокси Nginx

Примечание. Следующие операции выполняются на вашем удаленном сервере VPS, а не на локальном компьютере или в контейнере.

В настоящее время мы привязали контейнер к порту 8082, но пользователи не могут вручную ввести порт 8082 для доступа в Интернете. И если контейнер напрямую связан с портом 80, хотя пользователь может получить к нему прямой доступ без добавления порта, что, если есть второй контейнер или несколько контейнеров?

В это время вам нужно запустить Nginx на хост-компьютере, который монополизирует порт 80, а затем распределить запрос на отвечающий контейнер в соответствии с доменным именем. Как показано ниже:

nginx_anti-proxy

Эта схема называется «обратный прокси».

Войдите на сервер VPS и установите Nginx. Поскольку я Ubuntu, я могу использоватьaptУстановить.其他 Linux 发行版可以百度下安装方法,通常2行内可以搞定:

apt update # 更新软件包
apt-get install nginx # 安装 Nginx
systemctl status nginx # 查看 Nginx 状态

На этом этапе вы можете получить доступ к общедоступному IP-адресу VPS через браузер локально и увидеть страницу приветствия Nginx.

nginx_welcome

Затем на VPS-сервере/etc/nginx/conf.d/создатьvhost.confфайл со следующей конфигурацией:

server {
    listen 80;
    server_name pea3nut.info;

    location / {
        proxy_pass http://127.0.0.1:8082;
    }
}

Конфигурация означает мониторинг трафика с порта 80, если имя домена доступаpea3nut.info(замените своим доменным именем), все перенаправляется наhttp://127.0.0.1:8082середина

После завершения настройки перезапустите сервер Nginx. Если Ubuntu может использоватьsystemctl restart nginxКоманда, немного отличающаяся для разных дистрибутивов Linux

После успешной настройки посетитеpea3nut.infoувидит иVP S公网IP:8082тот же эффект

обновить сайт

После перехода на Docker процесс, который я хочу изменить, становится следующим:

  • Локальная модификация завершена, выполнитьgit push
  • Дождитесь завершения компиляции CI
  • Войдите на сервер VPS и выполните:
docker image pull pea3nut/pea3nut-info:latest
docker container create -p 8082:80 pea3nut/pea3nut-info:latest # 得到 yyy
docker container stop xxx # xxx 为当前运行的容器ID,可用 docker container ls 查看
docker container start yyy # yyy 第二条命令返回值

Команда все еще немного длинная? Мы будем дополнительно оптимизировать его ниже

Миграция сайта Nodejs (Express)

Далее мы фактически перенесем сайт Express SSR, написанный Nodejs.

что я собираюсь делать

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

  1. Измените Ejs или другие файлы локально
  2. Вручную загрузить на сервер через FTP
  3. Перезапустите процесс Nodejs на стороне сервера. Если есть какое-либо изменение зависимости пакета npm, его необходимо выполнить вручную на сервере VPS.npm install
  4. git pushОбновите исходный код Github

Это немного громоздко, поэтому я собираюсь изменить его следующим образом:

  1. воплощать в жизньgit push
  2. Автоматически определять наличие обновлений кода на github и автоматически упаковывать образ Docker.
  3. После компиляции CI подключитесь к VPS по SSH, удалите существующий контейнер и создайте новый контейнер с новым образом.

И польза от этого:

  1. Больше никаких ручных FTP-загрузок
  2. Нет необходимости вручную поддерживать среду выполнения Nodejs на сервере.

воплощать в жизнь

Особой разницы между конкретным процессом и обработкой статических сайтов нет, это не более чем:

  1. Написать Dockerfile
  2. Автоматически упаковывать изображения во время CI
  3. Добавьте обратный прокси Nginx к VPS

Я не буду повторяться в этот раз, конкретная конфигурация может ссылаться на соответствующие файлы в проекте.

Советы. Возможно, вы нашли файл Dockerfile вENTRYPOINTКоманда должна указывать процесс переднего плана. Если ваше приложение Nodejs поддерживается с помощью PM2, вам необходимо заменитьpm2 start app.jsдляpm2-docker app.js

docker-compose

Когда миграция сайта Nodejs завершена, у нас уже есть 2 контейнера, работающих на нашем VPS-сервере. Каждое обновление изображения должно выполняться вручнуюdocker container createПереносить кучу параметров может быть обременительно, особенно когда в будущем контейнеров становится все больше и больше. И вот, настала очередьdocker-composeПоявился~

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

docker-compose --help

Если вы работаете в Linux, вы можете установить docker-compose с помощью следующей команды:

curl -L "https://github.com/docker/compose/releases/download/1.23.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

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

Создайте каталог, затем создайте в каталогеdocker-compose.yml, содержание следующее:

version: "3.7" # 这个是配置文件的版本,不同的版本号声明方式会有细微的不同
services:
    info:
        container_name: pea3nut-info
        image: pea3nut/pea3nut-info:latest
        ports:
            - "8082:80"
        restart: on-failure

Затем введите следующую команду в каталоге для запуска службы:

docker-compose up info

docker-compose поможет нам автоматически извлекать образы, создавать контейнеры и80Сопоставление портов с хостом8082порт.restartПоле также просит docker-compose перезапустить контейнер, когда обнаруживает, что контейнер неожиданно зависает, подобно pm2, поэтому вам больше не нужно использовать pm2 внутри контейнера.

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

docker-compose pull info
docker-compose stop info
docker-compose rm info
docker-compose up -d info # -d 代表后台运行

Автор открыл исходный код своего метода развертывания веб-сайта, вы можете обратиться кgithub/pea3nut-hub

Миграция сайта WordPress (Apache + PHP + MySQL)

Далее мы фактически перенесем сайт WordPress.

  • URL-адрес:pea3nut.blog
  • Исходный код: закрытый

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

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

  1. Я не хочу раскрывать файлы данных MySQL и содержимое веб-сайта (например, изображения). Если они упакованы в образ, любой можетdocker image pullЗагрузите на зеркало, а затем получите файлы в зеркале
  2. При удалении контейнера сохраненные данные MySQL будут потеряны.

Volume

Docker предоставляет что-то под названием Volume, которое может «связать» папку в контейнере и хосте, и любые изменения файлов будут синхронизированы. Итак, я могу смонтировать весь каталог сайта и каталог MySQL как том. Таким образом, при удалении контейнера все файлы данных и исходный код сохраняются.

Создавайте локально./blog/mysql-dataКаталог для хранения данных MySQL, сборка./blog/wordpressВ каталоге хранится исходный код WordPress. затем изменитьdocker-compose.ymlследующим образом:

version: "3.7"
services:
    info:
        container_name: pea3nut-info
        image: pea3nut/pea3nut-info:latest
        ports:
            - "8082:80"
        restart: on-failure
+   blog:
+       container_name: pea3nut-blog
+       image: tutum/lamp:latest
+       ports:
+           - "8081:80"
+       volumes:
+           - ./blog/mysql-data:/var/lib/mysql
+           - ./blog/wordpress:/app
+       restart: on-failure

Видно, что в этот раз образ вообще не запакован, а используется напрямуюtutum/lampОтразите предоставленную среду LAMP (Linux + Apache + MySQL + PHP), затем поместите каталог данных MySQL/var/lib/mysqlи исходный каталог/appПросто загрузите все это

Советы: Через Volume мы как раз решили проблему деплоя, а как разрабатывать локально, а потом синхронизировать исходники на сервер? Использование FTP, конечно, возможно, но немного более громоздко. Фактически, вы можете создать свой собственный сервер Git! Видеть:pea3nut.blog/e127

Поговорки и другие трюки

исходный код

Миграция статического сайта (резюме автора):

Миграция сайта на PHP (блог автора):

Миграция Nodejs (официальный сайт Pxer):

разное:

  • Репозиторий, который объединяет конфигурации развертывания:GitHub.com/pea3nut/pea…

постскриптум

привет вотАрахис ПЭА. Спасибо, что прочитали эту статью, большое спасибо!

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

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

Но Docker действительно работает хорошо. После того, как весь сайт был докеризован, когда я снова мигрировал сервер, я обнаружил, что могу выполнить миграцию всей среды с помощью десяти строк команд, что заняло десять минут! Это «освежающее» чувство также мотивирует меня написать эту статью — я хочу поделиться этим освежением с вами перед экраном. Надеюсь, вам тоже нравится Docker ~ ❤️

Категории