• Как правильно организовать разработку на Laravel + Docker?

    У вас маленький проект и полноценный CI/CD к нему применить сложно - мало смысла в контейниризации, если нет необходимости скейлиться, балансировать и обеспечивать выживаемость сервиса. Разработка должна идти с использованием связки контейнеров с nginx, php-fpm, redis, postgresql и т.д. - при локальной разработке всё помещается в docker-compose.

    В проде - в вашем случае можно обойтись просто docker или с использованием того же docker-compose. В больших проектах на проде будет, например, kubernetes, nomad или docker swarm. Все контейнеры деплоятся и конфигурируются единожды. Ваш CI/CD должен собирать контейнер на основе alpine и php-fpm (для PHP) или nodejs (для nodejs, соответственно) с вашим проектом, желательно в пару стейджей для минимизации размеров окончательного образа, т.к. не нужен вам в проде композер, git, yarn, npm и прочие промежуточные штуки. И уже этот минимальный контейнер уезжает на прод.
    Ответ написан
    5 комментариев
  • Как пользоваться сервис контейнером в своих классах?

    mzcoding
    @mzcoding
    Web-Разработка
    Итак! Допустим у вас есть некая сущность для работы с платежами назовем ее Payment
    1. Создаем контракт и описываем (допустим) метод pay, отвечающий за (допустим) генерацию ссылки на оплату:
    namespace App\Contract;
    
    interface PaymentInterface
    {
       public function pay(): string;
    }

    2. Создаем сервис Payment и имплементим наш интерфейс + описываем метод pay и создаем конструктор еще, который (допустим) принимает некую ссылку на оплату (платежной системы) - Ссылку будем брать (допустим из конфига):
    namespace App\Service;
    
    use App\Contract\PaymentInterface;
    
    class Payment implements PaymentInterface
    {
        protected $paymentLink;
    
        public function __construct($paymentLink)
        {
            $this->paymentLink = $paymentLink;
        }
    
        public function pay(): string
        {
            return (string)$this->paymentLink;
        }
    }

    3. Создаем провайдер: php artisan make:provider PaymentProvider:
    namespace App\Providers;
    
    use App\Contract\PaymentInterface;
    use App\Service\Payment;
    use Illuminate\Support\ServiceProvider;
    
    class PaymentProvider extends ServiceProvider
    {
        /**
         * Register services.
         *
         * @return void
         */
        public function register()
        {
            $this->app->bind(PaymentInterface::class, function ($app) {
                return new Payment(config('app.payment_link'));
            });
        }
    
        /**
         * Bootstrap services.
         *
         * @return void
         */
        public function boot()
        {
            //
        }
    }

    4. Теперь надо зарегать наш провайдер в конфиге (config/app.php) - массив providers (в конец):
    App\Providers\PaymentProvider::class,

    5. Пропишем в config/app.php параметр payment_link:
    'payment_link' => 'https://money.yandex.ru’,

    6. Теперь создадим контроллер (или вызовем в существующем):
    namespace App\Http\Controllers;
    
    use App\Contract\PaymentInterface;
    
    class PaymentController
    {
        public function getPayment(PaymentInterface $payment)
        {
            dd($payment->pay());
        }
    
    }

    7. Готово )

    П.С: Обращаем внимание, что на вход принимаем интерфейс, а не реализацию
    П.П.С: Можно также вызывать в любом классе который зарегистрирован в контейнере.
    П.П.П.С: Можно юзать связывания без интерфейса (читаем в доке)

    Так-же можно вызвать ваш класс, через хелпер resolve (читаем в доке)

    Ссылка на доку: https://laravel.com/docs/5.8/container
    Ответ написан
    5 комментариев
  • Как вы используете Docker и npm / Composer при локальной разработке (папка node_modules / vendor)?

    andrhohlov
    @andrhohlov Автор вопроса
    Решение, протестированное на MacOS 10.14.3 и Windows 10 Pro.
    Есть куда улучшать, например можно добавить multi-stage build и т.д.. Но основная идея думаю останется такой.
    Минимальный пример, всё лишнее убрал.


    Используем один Dockerfile. Согласно best-practices, для кеширования слоёв, сначала ставим зависимости, затем копируем код, задаём не-рутового пользователя. Можно "выпекать" как есть и в продакшн.

    Dockerfile
    FROM node:10-alpine
    
    ARG NODE_ENV=production
    ENV NODE_ENV=${NODE_ENV}
    
    # Install latest npm
    RUN npm i npm@latest -g
    
    WORKDIR /usr/src/app
    
    # Instal dependencies
    COPY package*.json ./
    RUN npm install
    
    # Copy app code
    COPY ./src ./src
    
    # https://github.com/nodejs/docker-node/blob/master/docs/BestPractices.md#non-root-user
    USER node
    
    CMD ["node", "src/index.js"]

    В docker-compose.yaml для разработки мы:

    1. Задаём root пользователя, чтобы не иметь проблем с правами для установки зависимостей (спорный момент, возможно стоит просто разобраться с правами на директорию)
    2. Монтируем папку с кодом - теперь можем видеть изменения без пересборки образа. В этот момент установленные в этой папке внутри контейнера зависимости "исчезнут".
    3. Устанавливаем зависимости (теперь они видны и на хосте) и запускаем nodemon для отслеживания изменений. Мне понравился вариант объединить эти две команды, чтобы не выполнять дополнительно docker-compose exec api npm i после старта контейнера. При первом запуске нам в любом случае нужно поставить зависимости, последующие запуски или будут очень быстрыми, или доставят новые зависимости.

    docker-compose.yaml
    version: '3'
    
    services:
      api:
        environment:
          - NODE_ENV=development
        user: root
        build:
          context: ./api
          args:
            - NODE_ENV=development
        volumes:
          - ./api:/usr/src/app
        ports:
          - 3000:3000
        command: npm i && node_modules/.bin/nodemon src/index.js

    А теперь немного магии.
    Допустим, я занимаюсь исключительно PHP-частью проекта и мне все эти ваши node_modules на локальной машине не нужны.

    Создаём docker-compose.override.yml (должен быть в .gitignore) и переопределяем интересующие нас секции:

    docker-compose.override.yaml
    version: '3'
    
    services:
      api:
        volumes:
          - ./api:/usr/src/app
          - /usr/src/app/node_modules
        command: node_modules/.bin/nodemon src/index.js

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

    Или допустим я работаю на Windows и nodemon в Docker не реагирует на изменения файлов. Лечим:

    docker-compose.override.yaml
    version: '3'
    
    services:
      api:
        command: node_modules/.bin/nodemon --legacy-watch src/index.js


    Подробнее: https://docs.docker.com/compose/extends/

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

    * Конечно, тут могут возникнуть проблемы как с установкой и настройкой самого докера (в том числе поддержкой докера вашей операционной системой), так и работой более сложных конфигов. На мой взгляд, этот путь минимум не сложнее, чем настройка Vagrant'а и явно выигрывает у ручной установки (Python 2, Postgress и ещё чего-то когда твоя зона ответственности только шаблоны и стили, ой, а у тебя же уже стоит Python 3, и кстати по тому старому проекту надо Mongo 2 версии, так что делай что хочешь с установленной 3 версией...и объясни чуваку с WIndows как поставить nvm, чтобы версии Node.js переключать).
    Ответ написан
    Комментировать
  • Как использовать laravel passport для restfull api?

    @assets
    Back-end developer
    Можно использовать без jwt.

    $http = new GuzzleHttp\Client;
    
    $response = $http->post('http://your-app.com/oauth/token', [
        'form_params' => [
            'grant_type' => 'password',
            'client_id' => 'client-id',
            'client_secret' => 'client-secret',
            'username' => 'taylor@laravel.com',
            'password' => 'my-password',
            'scope' => '',
        ],
    ]);
    
    return json_decode((string) $response->getBody(), true);


    Передайте пароль и логин в ответ получите access_token

    дальше через header передайте access_token виде Bearer access_token

    345bfca0d2464b0aaf05093b849452e6.pngbb544728278e44b38939d799ed48daf4.png
    Ответ написан
    Комментировать