I wouldn’t use Docker if I lost my hair, died exhausted, and died in ICU.

Oh, mom, it smells good…

Hyperf In Docker

As one of the authors of Hyperf framework, strong Amway we use Docker, now Docker cluster technology has been very mature, K8s is a strong leader, deeply loved by first-line enterprises, and Swarm is simple to use, is absolutely the first choice of small and medium-sized enterprises.

But today, it’s not about the application of Hyperf in Docker, it’s about how the front end is packaged in Docker and communicates with Hyperf.

packaging

Let’s take VUE as an example. Here is a repository vue-docker-demo for you to test.

First we initialize a project using vue scaffolding.

vue create vue-docker-demoCopy the code

Next we initialize the Hyperf project, and for the sake of explanation, the back-end project is also uploaded to this repository.

cd vue-docker-demo
composer create hyperf/biz-skeleton hyperfCopy the code

Modify Hyperf project to facilitate testing

Create a UserController controller

<? php declare(strict_types=1); namespace App\Controller; class UserController extends Controller { public function info(int $id) { return $this->response->success([ 'id' => $id,  'name' => 'Hyperf', ]); } public function update(int $id) { $name = $this->request->input('name'); return $this->response->success([ 'id' => $id, 'name' => $name, ]); }}Copy the code

Add the routing

<? php Router::get('/user/{id:\d+}', 'App\Controller\UserController@info'); Router::post('/user/{id:\d+}', 'App\Controller\UserController@update');Copy the code

Adding unit tests

<?php

declare(strict_types=1);

namespace HyperfTest\Cases;

use HyperfTest\HttpTestCase;

/**
 * @internal
 * @coversNothing
 */
class UserTest extends HttpTestCase
{
    public function testUserInfo()
    {
        $res = $this->get('/user/1');

        $this->assertSame(0, $res['code']);
        $this->assertSame(['id' => 1, 'name' => 'Hyperf'], $res['data']);
    }

    public function testUserUpdate()
    {
        $res = $this->json('/user/1', [
            'name' => 'limx',
        ]);

        $this->assertSame(0, $res['code']);
        $this->assertSame(['id' => 1, 'name' => 'limx'], $res['data']);
    }
}
Copy the code

Run the interface tests

$ composer test > co-phpunit -c phpunit.xml --colors=always Detected an available cache, skip the app scan process. Detected an available cache, skip the vendor scan process. [DEBUG] Event Hyperf\Framework\Event\BootApplication handled by Hyperf\Di\Listener\BootApplicationListener listener. [DEBUG] Event Hyperf\Framework\Event\BootApplication handled by Hyperf\Config\Listener\RegisterPropertyHandlerListener listener. [DEBUG] Event Hyperf\Framework\Event\BootApplication Handled by Hyperf\Paginator\Listener\PageResolverListener Listener. PHPUnit 7.5.16 by Sebastian Bergmann and contributors. ... 3/3 (100%) Time: 309 ms, Memory: 16.00 MB OK (3 tests, 14 assertions)Copy the code

Revamp VUE project

My front-end skills are limited, so I wrote some simple tests, mainly for experimentation
Dockerfile.


Install AXIOS using NPM

npm i axios -SCopy the code

Add request. Js

import axios from 'axios' export default { async request(method, url, params) { const BASE_URI = '/api'; return axios({ method: method, url: `${BASE_URI}${url}`, data: params, }); }}Copy the code

Modify helloWorld.vue. The following shows only the modified parts

<script> import request from ".. /api/request"; export default { name: 'HelloWorld', messaage: '', props: { msg: String }, async mounted() { var data = await request.request('GET', '/user/1'); // eslint-disable-next-line no-console console.log(data); var res = await request.request('POST', '/user/1', { name: "limx" }); // eslint-disable-next-line no-console console.log(res); } } </script>Copy the code

Add Dockerfile and app.conf

First, when nginx takes the/API prefix, it forwards it to the corresponding back-end service, so you need to provide an app.conf configuration

server { listen 80; root /usr/src/app/dist; index index.html; client_max_body_size 8M; proxy_set_header Host $host:$server_port; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-PORT $remote_port; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; location /api/ { proxy_pass http://biz-skeleton:9501/; }}Copy the code

Next is our Dockerfile, the logic is actually very simple, we first through the Node environment package, and then copy to the nginx environment can be.

FROM node:10-alpine as builder WORKDIR /usr/src/build ADD package.json /usr/src/build ADD package-lock.json /usr/src/build RUN npm install -g cnpm --registry=https://registry.npm.taobao.org && cnpm install COPY . /usr/src/build RUN npm run-script build FROM nginx:alpine COPY --from=builder /usr/src/build/dist /usr/src/app/dist COPY --from=builder  /usr/src/build/app.conf /etc/nginx/conf.d/ ENTRYPOINT ["nginx", "-g", "daemon off;"]Copy the code

Packaging test

First go to our Hyperf directory and package the back-end services

cd hyperf
docker build . -t biz-skeleton:latestCopy the code

And then package up our front-end code

docker build . -t vue-demoCopy the code

Create a gateway. If one has already been created, you can ignore this and use the gateway you created

$docker network create \ --subnet 10.0.0.0/24 \ --opt encrypted \ --attachable \ default-networkCopy the code

Next, let’s run both projects

docker run -p 9501:9501 --name biz-skeleton --network default-network --rm -d biz-skeleton:latest
docker run -p 8080:80 --name vue-demo --network default-network --rm -d vue-demo:latestCopy the code

Then visit http://127.0.0.1:8080/ through your browser

You can see our test results in the terminal output.

release

DockerSwarm DockerSwarm DockerSwarm DockerSwarm DockerSwarm DockerSwarm DockerSwarm DockerSwarm DockerSwarm

It is also necessary to mention that it is very wasteful for static files to go through the public network traffic of the server every time. It is recommended to use CDN and configure a back source, which can greatly reduce the traffic pressure. Of course, it is not good to cache the data returned by the interface to the CDN.

Write in the last

hyperf/hyperf

Hyperf is a high performance and high flexibility PHP coroutine framework based on Swoole 4.4+. The built-in coroutine server and a large number of commonly used components have a qualitative improvement in performance compared with the traditional PHP-FPm-based framework. While providing ultra high performance, Hyperf also maintains extremely flexible scalability. Standard components are based on PSR standards, based on a strong dependency injection design, to ensure that most components or classes are replaceable and reusable.

Framework component library in addition to the common coroutine version of MySQL client, Redis client, Eloquent ORM, WebSocket server and client, JSON RPC server and client, GRPC server and client, Zipkin/Jaeger (OpenTracing) client, Guzzle HTTP Client, Elasticsearch client, Consul client, ETCD client, AMQP component, Apollo Configuration Center, ALiccloud ACM Application Configuration Management, ETCD Configuration Center, Token bucket algorithm based flow Limiter, Universal Connection Pool, Fuse, Swagger Document generation, Swoole Tracker, Blade and Smarty view engines, Snowflake global ID generator, and more save you the trouble of implementing your own version of the coroutine.

Hyperf also provides pSR-11-based dependency injection containers, annotations, AOP aspect oriented programming, PSR-15-based middleware, custom processes, PSR-14-based event managers, Redis/RabbitMQ message queues, automatic model caching, and PSR-16-based It has convenient functions such as cache, Crontab second scheduled task, Translation internationalization, Validation validator, etc., which can meet rich technical scenarios and business scenarios, out of the box.