php 调用 docker 服务

背景

最近在使用一个云产品,网上看到了相关的api镜像,直接运行容器即可简单操作。如何使用 php 操作呢?于是查了相关的东西,最后完成到自己的项目中。这篇文章记录一下使用过程。官方提供了 golang、python和http的 API调用,社区也做好了各种语言的SDK,有需要的都可以用起来。

Language Library
C libdocker
C# Docker.DotNet
C++ lasote/docker_client
Dart bwu_docker
Erlang erldocker
Gradle gradle-docker-plugin
Groovy docker-client
Haskell docker-hs
HTML (Web Components) docker-elements
Java docker-client
Java docker-java
Java docker-java-api
NodeJS dockerode
NodeJS harbor-master
Perl Eixo::Docker
PHP Docker-PHP
Ruby docker-api
Rust docker-rust
Rust shiplift
Scala tugboat
Scala reactive-docker
Swift docker-client-swift

用法

通过composer添加依赖:

composer require docker-php/docker-php

可以查看社区文档获得更详细的使用方法:https://docker-php.readthedocs.io/en/latest/

连接docker

按常规的方式,如果不做docker配置,则会将其unix:///var/run/docker.sock用作默认配置连接docker。

由于本地的程序是运行在容器里的,所以当然没有这个文件,只能通过tcp方式连接,在服务器上可以通过把宿主机的docker.sock文件映射到容器里进行读取.

值得注意的是,代码中我使用了10.0.75.1:2376这样的地址。IP地址是Windows中源主机的ip,Windows中记得打开docker的访问地址:

54495809413

你应该也注意到了我使用的不是2375端口,因为这个端口只能是127.0.0.1地址才能访问,所以我做了一个转发,你在Windows下开发的时候也要这么做:

netsh interface portproxy add v4tov4 listenport=2376 connectaddress=127.0.0.1 connectport=2375

实现代码如下:


    public static function getClient(){
        if (app()->environment('local')) {
            $client = DockerClientFactory::create([
                'remote_socket' => 'tcp://10.0.75.1:2376',
                'ssl' => false,
            ]);
        } else {
            $client = null;
        }

        return $client;
    }
    
    public static function dockerTest(){
        $cfg = self::getClient();
        if($cfg){
            $docker = Docker::create($cfg);
        }else{
            $docker = Docker::create();
        }

        $containers = $docker->containerList(["all"=>true]);
        foreach ($containers as $container) {
            echo $container->getNames()[0]. "\n";
            if ($container->getState() == 'exited') {
                $docker->containerDelete($container->getId());
            }
        }
    }    

创建容器

设置好所需的镜像和环境变量,再运行即可。敏感的变量我使用了xxx进行替代。


    public static function setConfig($endPoint, $apiKey, $secretKey, $type)
    {
        $containerConfig = new ContainersCreatePostBody();
        $containerConfig->setImage('xxxx');
        $containerConfig->setEnv([
            "END_POINT=" . $endPoint,
            "API_KEY=" . $apiKey,
            "SECRET_KEY=" . $secretKey
        ]);

        $containerConfig->setAttachStdin(true);
        $containerConfig->setAttachStdout(true);
        $containerConfig->setAttachStderr(true);
        switch ($type) {
            case "xxxx":
                break;
            default:
        }

        return $containerConfig;
    }

    public static function basic($func,$cmd = "xxx"){
        $cfg = self::getClient();
        $docker = $cfg ? Docker::create($cfg) : Docker::create();

        foreach (Account::$configs as $key => $config) {
            foreach (Account::$apis as $api) {
                $containerCreateResult = $docker->containerCreate(self::setConfig($api, $config[0], $config[1], $cmd));
                echo $containerCreateResult->getId()."\n";
                $id = $containerCreateResult->getId();
                $attachStream = $docker->containerAttach($id, [
                    'stream' => true,
                    'stdin' => true,
                    'stdout' => true,
                    'stderr' => true
                ]);
                $docker->containerStart($id);

                $output = '';
                $attachStream->onStdout(function ($stdout) use (&$output) {
                    $output .= $stdout;
                });

                $attachStream->wait();

                $result = json_decode($output);

                if (!$result) dd("idcf no return value");

                self::$func($result);
                $docker->containerDelete($id);
            }
        }
    }

参考资料


这可能是人工智能、机器学习和大数据领域覆盖最全的一份速查表 - InfoQ 日本那个绚烂,疯狂,却又转瞬即逝的时代 - 微观当代