Laravel має потужний CLI-фреймворк, що базується на популярному компоненті Symfony Console, який приносить основні можливості Laravel у командний рядок. Хоча зазвичай Laravel використовується для створення веб-додатків, деякі проекти потребують надійних CLI-команд, які можна запускати через Docker у виробничих середовищах.
Якщо ви розробляєте проект лише з CLI, можете також розглянути використання спільного проекту Laravel Zero. Усе, що ми обговорюємо в цій статті, працює як з Laravel, так і з Laravel Zero (з деякими налаштуваннями образу Docker).
Ми створимо невеличкий CLI для перевірки акцій (за допомогою API Polygon.io), який ви зможете запускати через Docker. Він матиме підкоманди для перевірки акцій. Зокрема, ми реалізуємо команду stock:check
, яка буде шукати акції за вказаною датою, використовуючи символ акції:
php artisan stock:check AAPL
На момент написання, Polygon.io пропонує безкоштовний базовий план API, що дозволяє виконувати 5 запитів на хвилину і має дані за останні два роки. Щоб продовжити, вам знадобиться ключ API. Він також дозволить ілюструвати, як налаштувати секрети для використання з нашим Docker-образом.
Спочатку створимо проект Laravel. Якщо ви слідуєте за нами, потрібно встановити PHP та Laravel Installer:
laravel new stock-checker --git --no-interaction
Оскільки наша програма буде лише CLI, нам не потрібні жодні стартові набори, тому використаємо параметр --no-interaction
, щоб прийняти всі значення за замовчуванням. Якщо ви зможете виконати php artisan inspire
після створення проекту stock-checker, ви готові до початку:
php artisan inspire
“Я починаю говорити лише тоді, коли впевнений, що те, що я скажу, не варто залишити невисловленим.”
— Катон Молодший
На завершення, потрібно створити кілька файлів для роботи з Docker під час розробки, хоча кінцеві користувачі потребують лише середовища виконання для використання програми:
mkdir build/
touch \
.dockerignore \
compose.yaml \
build/Dockerfile
Файл Dockerfile
знаходиться в папці build
. Я віддаю перевагу зберігати файли конфігурації Docker у підкаталогах для кращої організації, враховуючи такі речі, як INI-файли та інші проекти, пов'язані з Docker.
У нас є усе необхідне для старту. У наступному розділі ми створимо команду і налаштуємо додаток для роботи з Docker.
Наш додаток почнеться з однієї команди check
, яка шукатиме деталі акцій США за вказаним символом. Ми не будемо зосереджуватися на вмісті цього файлу, але якщо ви хочете слідувати інструкції, створіть файл команди з Artisan:
php artisan make:command CheckStockCommand
Додайте наступний код до щойно створеного файлу CheckStockCommand.php
, який знаходиться в папці app/Console/Commands
:
<?php
namespace App\Console\Commands;
use Illuminate\Http\Client\PendingRequest;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;
use Illuminate\Console\Command;
class CheckStockCommand extends Command
{
protected $signature = 'stock:check {symbol} {--d|date= : Дата, для якої потрібно перевірити ціну акцій}';
protected $description = 'Перевірити ціну акцій за вказаним символом.';
public function handle()
{
$symbol = Str::upper($this->argument('symbol'));
// Отримати найближчий торгівельний будній день.
$date = now()->previousWeekday();
if ($dateOption = $this->option('date')) {
$date = Carbon::parse($dateOption);
if ($date->isToday() || $date->isFuture()) {
$this->error('Дата повинна бути в минулому.');
return;
}
}
if ($date->lt(now()->subYear())) {
$this->error('Дата повинна бути в межах останнього року.');
return;
}
// Знайти дані про акції
$ticker = $this->getClient()
->withUrlParameters(['symbol' => $symbol])
->withQueryParameters(['date' => $date->toDateString()])
->throw()
->get("https://api.polygon.io/v3/reference/tickers/{symbol}")
->json('results');
$openClose = $this->getClient()
->withUrlParameters([
'symbol' => $symbol,
'date' => $date->toDateString()
])
->get("https://api.polygon.io/v1/open-close/{symbol}/{date}?adjusted=true");
if ($openClose->failed()) {
$this->error("Не вдалося отримати дані акцій.\nСтатус: " . $openClose->json('status') . "\nПовідомлення: " . $openClose->json('message') . "\n");
return;
}
$this->info("Акція: {$ticker['name']} ({$ticker['ticker']})");
$this->info("Дата: {$date->toDateString()}");
$this->info("Валюта: {$ticker['currency_name']}");
$this->table(['Відкриття', 'Закриття', 'Максимум', 'Мінімум'], [
[
number_format($openClose['open'], 2),
number_format($openClose['close'], 2),
number_format($openClose['high'], 2),
number_format($openClose['low'], 2),
],
]);
}
protected function getClient(): PendingRequest
{
return Http::withToken(config('services.polygon.api_key'));
}
}
Ця команда терміналу знаходить символ акцій за минулу дату в межах останнього року та повертає основну інформацію про акцію на цю дату. Щоб команда працювала, потрібно налаштувати конфігурацію сервісу і визначити дійсний ключ. Додайте наступну конфігурацію у файл config/services.php
, який команда використовуватиме для налаштування ключа API:
// config/services.php
return [
// ...
'polygon' => [
'api_key' => env('POLYGON_API_KEY'),
],
];
Не забудьте додати POLYGON_API_KEY
до вашого .env
файлу, а також додати змінну середовища до .env.example
як порожнє значення:
# .env
POLYGON_API_KEY="<ваш_секретний_ключ>"
# .env.example
POLYGON_API_KEY=
Якщо ви запустите команду локально з дійсним символом акції, отримаєте щось на зразок цього:
php artisan stock:check AAPL
Акція: Apple Inc. (AAPL)
Дата: 2024-10-25
Валюта: usd
+--------+--------+--------+--------+
| Відкриття | Закриття | Максимум | Мінімум |
+--------+--------+--------+--------+
| 229.74 | 231.41 | 233.22 | 229.57 |
+--------+--------+--------+--------+
Ми перевірили, що команда працює, і тепер час створити Docker-образ для нашого CLI. Docker дозволяє кожному використовувати наш CLI без необхідності знати, як налаштувати середовище виконання.
Останнє, що ми зробимо перед створенням Docker-образу — це додати файл .env
до .dockerignore
, щоб не копіювати чутливі дані під час створення образу:
.env
Готові налаштувати CLI для роботи з Docker. Існує кілька типових випадків використання для CLI-образу Docker:
Усі ці випадки застосовні до того, як ми налаштуємо Dockerfile
. У цій статті ми розглянемо кілька способів структурування образу для CLI. Ми врахуємо запуск нашого CLI як єдиної команди або можливість забезпечити користувачам виконання кількох підкоманд.
Наш Dockerfile
базується на офіційному образі PHP CLI і використовуватиме інструкцію ENTRYPOINT, щоб зробити команду stock:check
єдиною командою, яка може виконуватися з образу. Без переозначення точки входу всі команди, які передаються нашому образу, виконуватимуться у контексті команди stock:check
:
FROM php:8.3-cli-alpine
RUN docker-php-ext-install pcntl
COPY . /srv/app
WORKDIR /srv/app
ENTRYPOINT ["php", "/srv/app/artisan", "stock:check"]
CMD ["--help"]
Примітка: встановлення розширення pcntl у Docker CLI проектах дозволяє м’яко завершувати контейнери Docker за допомогою процесних сигналів. Ми не демонструємо це в цій команді, але якщо у вас є довготривалий демон, вам потрібно буде обробити м’яке завершення в будь-якому серверному середовищі, включаючи контейнери.
Інструкція ENTRYPOINT вказує команду, яка виконується під час запуску контейнера. Найцікавіше в цьому контексті — що всі команди, які ми передаємо контейнеру при його запуску, «додаються» до точки входу. Спробую пояснити:
# ENTRYPOINT # Значення за замовчуванням CMD
php artisan stock:check --help
# Вище еквівалентно виконанню наступного:
docker run --rm stock-checker
# ENTRYPOINT # Замініть значення CMD
php artisan stock:check AAPL
# Вище еквівалентно виконанню:
docker run --rm stock-checker AAPL
Ми показали, що ENTRYPOINT дозволяє виконувати одну команду, але якщо ви внесете цю невелику зміну, зможете запустити будь-яку команду, доступну в консолі Artisan:
FROM php:8.3-cli-alpine
RUN docker-php-ext-install pcntl
COPY . /srv/app
WORKDIR /srv/app
ENTRYPOINT ["php", "/srv/app/artisan"]
CMD ["list"]
Тепер точка входу — це artisan
, що надає можливість виконувати будь-яку команду в консольному Artisan. Якщо ви розповсюджуєте CLI для інших користувачів, не рекомендується відкривати команди, окрім тих, що ви визначили, але наразі вони можуть запускати всі команди, доступні у вашому додатку.
Виконання команди php artisan list
стане значенням за замовчуванням при запуску Docker-образу без аргументів команди. Тепер ми можемо легко запускати нашу команду перевірки акцій та інші команди для нашого CLI так:
docker build -t stock-checker -f build/Dockerfile .
# Запустити перевірку акцій
export POLYGON_API_KEY="<ваш_ключ>"
docker run --rm --env POLYGON_API_KEY stock-checker stock:check AAPL
Частини stock:check
та AAPL
тепер складають CMD. Раніше stock:check
була єдиною командою, яку CLI міг виконувати без переозначення точки входу (це можна зробити за допомогою параметра --entrypoint=
з docker run
).
Зверніть увагу, що наш CLI вимагає змінної середовища для налаштування облікових даних. Використовуючи параметр --env
, ми можемо передавати локальну змінну ENV, яку ми експортували. Залежно від потреб вашого додатку ви могли б надати конфігураційний файл, з якого CLI зчитує дані з секретного обсягу. Для зручності цієї статті ми використовуємо вбудовані можливості ENV Docker для запуску CLI.
Якщо вам потрібно запустити команду CLI у вашому додатку Laravel через Docker, зазвичай ви маєте php-fpm
образ Docker, що містить ваш веб-додаток/API. Замість того, щоб створювати окремий образ CLI, ви можете налаштувати точку входу та команду для запуску як консолі Artisan замість веб-додатку. Усе виглядатиме схоже на вже наявне, а перевага в тому, що ви можете повторно використовувати образ веб-додатку для запуску CLI:
docker run --rm my-app --entrypoint=/srv/app/artisan stock:check AAPL
Це основи запуску Laravel CLI з Docker, використовуючи ENTRYPOINT для визначення базової команди, яку наш Docker-образ використовуватиме для виконання команд. Ви можете дізнатися більше про entrypoint і cmd у офіційній довідці Dockerfile.