Requesting Image Information using the Public Docker API

Scenario

You are writing some kick ass docker application, or trying to script some kick ass automation that requires obtaining docker images information without having to pull the image down to your boot2docker/server and after countless hours, a little sleep, and then countless more hours.. you still can’t figure out what the heck you need to actually do. You see incomplete reference after incomplete reference in the docker documentation that alludes to having to obtain an authorization token in order to query the registry, but no concrete articles appear to exist, even in the deepest, darkest, places that live on the interwebs, that seem to clearly explain how the heck this is actually done.. Until now…..

Background

A little bit of background is helpful, so the first thing that you may have discovered on this impossible journey is that Docker has divided their API into 2 different APIs.

  • Docker Hub API – This is the API which allows anyone unauthorized access to a repository image information such as the image description, number of starts, if its an official image, and image layer ids, but no specific information on the image itself.
  • Docker Registry API – This is the API that will allow a return response containing specific information such as environment variables, Exposed Ports, Volumes, etc from an image on the registry, however in order to request this information, an Authorization token is required PER request. This Authorization token must be requested from the Docker Hub, and then included in the request to the Docker registry in order to allow a request to be responded to with the desired information. Tokens also are only good for a single request. Each time a request is made for image information, even the same image, a new token will be required.
  • After understanding the request flow, lets dive right in and see how we go about getting an auth token and sending that token to get image information returned to us.

    Search for a specific image

    The first thing we need to do is get an image that we would like to know more information about. This can be done by either going to the docker hub and searching for a desired image, or using the Docker Hub API to search for us. So lets say we are looking for information on an image containing SonarQube. First we will need to search the public hub for images that are labeled as sonarqube, or contain the namespace of sonarqube.



    Standard API Request


    https://index.docker.io/v1/search?q=sonarqube
    

    Docker API Search



    Standard API Response



    This will return a response listing out all of the eligible images in JSON format. The Docker Search API only returns 10 results.

    {
      "num_pages": 1,
      "num_results": 10,
      "results": [
        {
          "is_automated": false,
          "name": "sonarqube",
          "is_trusted": false,
          "is_official": true,
          "star_count": 18,
          "description": "SonarQube is an open source platform for continuous inspection of code quality."
        },
        {
          "is_automated": true,
          "name": "lstephen/sonarqube",
          "is_trusted": true,
          "is_official": false,
          "star_count": 1,
          "description": "Dockerized SonarQube server"
        },
        {
          "is_automated": true,
          "name": "harbur/sonarqube",
          "is_trusted": true,
          "is_official": false,
          "star_count": 4,
          "description": ""
        },
        {
          "is_automated": true,
          "name": "webdizz/sonarqube",
          "is_trusted": true,
          "is_official": false,
          "star_count": 1,
          "description": ""
        },
        {
          "is_automated": true,
          "name": "npalm/sonarqube",
          "is_trusted": true,
          "is_official": false,
          "star_count": 0,
          "description": ""
        },
        {
          "is_automated": true,
          "name": "ototadana/sonarqube",
          "is_trusted": true,
          "is_official": false,
          "star_count": 0,
          "description": ""
        },
        {
          "is_automated": true,
          "name": "rocklass/sonarqube",
          "is_trusted": true,
          "is_official": false,
          "star_count": 0,
          "description": "SonarQube image"
        },
        {
          "is_automated": true,
          "name": "gamars/sonarqube",
          "is_trusted": true,
          "is_official": false,
          "star_count": 0,
          "description": "Dockerized SonarQube instance"
        },
        {
          "is_automated": true,
          "name": "appcontainers/sonarqube",
          "is_trusted": true,
          "is_official": false,
          "star_count": 0,
          "description": "CentOS 6.6 SonarQube 4.5.1 Container Build - 652.5 MB"
        },
        {
          "is_automated": true,
          "name": "leehanwool/sonarqube",
          "is_trusted": true,
          "is_official": false,
          "star_count": 0,
          "description": ""
        }
      ],
      "page_size": 25,
      "query": "sonarqube",
      "page": 1
    }



    Curl Request


    curl -si https://index.docker.io/v1/search?q=sonarqube
    



    Curl Response



    This will return the response header, as well as a listing of the eligible images in JSON format. The Docker Search API only returns 10 results.

    HTTP/1.1 200 OK
    Server: nginx/1.6.2
    Date: Fri, 19 Jun 2015 19:31:34 GMT
    Content-Type: application/json
    Transfer-Encoding: chunked
    Connection: close
    Vary: Cookie
    X-Frame-Options: SAMEORIGIN
    Strict-Transport-Security: max-age=3153600
     
    {"num_pages": 1, "num_results": 10, "results": [{"is_automated": false, "name": "sonarqube", "is_trusted": false, "is_official": true, "star_count": 18, "description": 
    "SonarQube is an open source platform for continuous inspection of code quality."}, {"is_automated": true, "name": "lstephen/sonarqube", "is_trusted": true, 
    "is_official": false, "star_count": 1, "description": "Dockerized SonarQube server"}, {"is_automated": true, "name": "harbur/sonarqube", "is_trusted": true, 
    "is_official": false, "star_count": 4, "description": ""}, {"is_automated": true, "name": "webdizz/sonarqube", "is_trusted": true, "is_official": false, "star_count": 1,
     "description": ""}, {"is_automated": true, "name": "npalm/sonarqube", "is_trusted": true, "is_official": false, "star_count": 0, "description": ""}, 
    {"is_automated": true, "name": "ototadana/sonarqube", "is_trusted": true, "is_official": false, "star_count": 0, "description": ""}, 
    {"is_automated": true, "name": "rocklass/sonarqube", "is_trusted": true, "is_official": false, "star_count": 0, "description": "SonarQube image"}, 
    {"is_automated": true, "name": "gamars/sonarqube", "is_trusted": true, "is_official": false, "star_count": 0, "description": "Dockerized SonarQube instance"}, 
    {"is_automated": true, "name": "appcontainers/sonarqube", "is_trusted": true, "is_official": false, "star_count": 0, 
    "description": "CentOS 6.6 SonarQube 4.5.1 Container Build - 652.5 MB"}, {"is_automated": true, "name": "leehanwool/sonarqube", "is_trusted": true, 
    "is_official": false, "star_count": 0, "description": ""}], "page_size": 25, "query": "sonarqube", "page": 1}

    So parsing through the available images, we see that it just so happens that there is an appcontainers sonarqube image. Here at Appcontainers, we happen to like appcontainer images, so lets use that for our example !

    Get Authorization Token For a specific image

    Now that we have determined that we want to more information on the appcontainers/sonarqube container image, without downloading it, the next easy, but really poorly documented step is requesting a token from the Docker hub, to use on the Docker registry to see the image details. In order to do this, we must make an API request to the Docker hub and pass the header parameter of X-Docker-Token: true

  • In order to do this in an extention tool like PostMan.. Click on the Headers section and type in X-Docker-Token in the Header Section, and true in the Value section prior to sending the request.


  • Standard API Request


    https://registry.hub.docker.com/v1/repositories/appcontainers/sonarqube/images
    



    Standard API Request Header


    X-Docker-Token: true
    

    Docker API Token Request


    Standard API Response


    This response will give us 2 vital pieces of information in 2 different places. The first is the image ID, which will be found in the body section of the response. The second being the actual auth token which can be found in the header section of the response.

  • In order to request the image information we only need the top image ID from the body of the response.
  • [
      {
        "checksum": "",
        "id": "2e77f2b2443b62e01b25fc5831d884c447ac41b8cfea85d67045e7da483a1a6f"
      },
      {
        "checksum": "",
        "id": "88434a88a1965e4acf6bf489a7919df0d646d8e91a442ca817e371f78b95a67d"
      },
      {
        "checksum": "",
        "id": "083da660cebf2d7b902c3f6f1fb5591721c7d59bd06b2fd95dd4fbce66b6adba"
      },
    etc...
    ]



    Standard API Response Header


    Docker API Token Response Header

    Connection → close
    Content-Type → application/json
    Date → Fri, 19 Jun 2015 19:42:21 GMT
    Server → nginx/1.6.2
    Strict-Transport-Security → max-age=3153600
    Transfer-Encoding → chunked
    Vary → Cookie
    X-Docker-Endpoints → registry-1.docker.io
    X-Docker-Token → signature=1321a16a92a45b3a9dab4c26c99d94328e54401e,repository="appcontainers/sonarqube",access=read
    X-Frame-Options → SAMEORIGIN
    

    The most important piece of the response header is the X-Docker-Token

    signature=1321a16a92a45b3a9dab4c26c99d94328e54401e,repository="appcontainers/sonarqube",access=read
    



    Curl Request



    This curl request will do the same as a standard API request, but we will cut off all of the additional image layers, and just return the first, with the header information showing.

    curl -si https://registry.hub.docker.com/v1/repositories/appcontainers/sonarqube/images -H 'X-Docker-Token: true' | awk '{print $1, $2, $4}'
    



    Curl Response


    * Image
    <pre>
    HTTP/1.1 200 
     erver: nginx/1.6.2
    Date: Fri, Jun
     ontent-Type: application/json
     ransfer-Encoding: chunked
     onnection: close
     ary: Cookie
     -Docker-Endpoints: registry-1.docker.io
     -Frame-Options: SAMEORIGIN
     -Docker-Token: signature=44169a5eb2718aac8caaa07ed80f261e687b374c,repository="appcontainers/sonarqube",access=read
     trict-Transport-Security: max-age=3153600
     
    [{"checksum": "", "2e77f2b2443b62e01b25fc5831d884c447ac41b8cfea85d67045e7da483a1a6f"},

    Again the most import pieces from this response output are the Image ID, and the Token

    2e77f2b2443b62e01b25fc5831d884c447ac41b8cfea85d67045e7da483a1a6f
    
    signature=44169a5eb2718aac8caaa07ed80f261e687b374c,repository="appcontainers/sonarqube",access=read
    

    Get Image Information Using the new Token

  • At this point you have both of the pieces of information required to query the image data..
  • The Image ID from the body response
    The X-Docker-Token from the header response

    Lets get some Data!!!



    Standard API Request


  • In order to do this in an extension tool like PostMan.. Click on the Headers section and type in Authorization in the Header Section, and the Token signature line in the Value section prior to sending the request.
  • https://cdn-registry-1.docker.io/v1/images/2e77f2b2443b62e01b25fc5831d884c447ac41b8cfea85d67045e7da483a1a6f/json
    



    Standard API Request Header


    Authorization: Token signature=1321a16a92a45b3a9dab4c26c99d94328e54401e,repository="appcontainers/sonarqube",access=read
    

    Docker Registry API Response



    Standard API Response


    {
      "id": "2e77f2b2443b62e01b25fc5831d884c447ac41b8cfea85d67045e7da483a1a6f",
      "parent": "88434a88a1965e4acf6bf489a7919df0d646d8e91a442ca817e371f78b95a67d",
      "created": "2015-02-11T15:51:22.129586647Z",
      "container": "01ee15edd65ba42c68ef40d8464ae9e1e4e2867af5d131ed40e0b8acc6184100",
      "container_config": {
        "Hostname": "4338b33adb2a",
        "Domainname": "",
        "User": "",
        "Memory": 0,
        "MemorySwap": 0,
        "CpuShares": 0,
        "Cpuset": "",
        "AttachStdin": false,
        "AttachStdout": false,
        "AttachStderr": false,
        "PortSpecs": null,
        "ExposedPorts": {
          "9000/tcp": {}
        },
        "Tty": false,
        "OpenStdin": false,
        "StdinOnce": false,
        "Env": [
          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
          "RUNNERVER=sonar-runner-dist-2.4",
          "MYSQL_SERVER=localhost",
          "MYSQL_PASS=PAssw0rd",
          "MYSQL_DB=sonar",
          "APP_USER=admin",
          "APP_PASS=Passw0rd"
        ],
        "Cmd": [
          "/bin/sh",
          "-c",
          "#(nop) EXPOSE map[9000/tcp:{}]"
        ],
        "Image": "88434a88a1965e4acf6bf489a7919df0d646d8e91a442ca817e371f78b95a67d",
        "Volumes": null,
        "WorkingDir": "",
        "Entrypoint": null,
        "NetworkDisabled": false,
        "MacAddress": "",
        "OnBuild": []
      },
      "docker_version": "1.4.1",
      "author": "Rich Nason rnason@appcontainers.com",
      "config": {
        "Hostname": "4338b33adb2a",
        "Domainname": "",
        "User": "",
        "Memory": 0,
        "MemorySwap": 0,
        "CpuShares": 0,
        "Cpuset": "",
        "AttachStdin": false,
        "AttachStdout": false,
        "AttachStderr": false,
        "PortSpecs": null,
        "ExposedPorts": {
          "9000/tcp": {}
        },
        "Tty": false,
        "OpenStdin": false,
        "StdinOnce": false,
        "Env": [
          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
          "RUNNERVER=sonar-runner-dist-2.4",
          "MYSQL_SERVER=localhost",
          "MYSQL_PASS=PAssw0rd",
          "MYSQL_DB=sonar",
          "APP_USER=admin",
          "APP_PASS=Passw0rd"
        ],
        "Cmd": [
          "/bin/sh",
          "-c",
          "/bin/bash"
        ],
        "Image": "88434a88a1965e4acf6bf489a7919df0d646d8e91a442ca817e371f78b95a67d",
        "Volumes": null,
        "WorkingDir": "",
        "Entrypoint": null,
        "NetworkDisabled": false,
        "MacAddress": "",
        "OnBuild": []
      },
      "architecture": "amd64",
      "os": "linux",
      "checksum": "tarsum.dev+sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
      "Size": 0
    }



    Curl Request


    curl https://cdn-registry-1.docker.io/v1/images/2e77f2b2443b62e01b25fc5831d884c447ac41b8cfea85d67045e7da483a1a6f/json 
    -H 'Authorization: Token signature=44169a5eb2718aac8caaa07ed80f261e687b374c,repository="appcontainers/sonarqube",access=read'
    



    Curl Response


    {"id":"2e77f2b2443b62e01b25fc5831d884c447ac41b8cfea85d67045e7da483a1a6f","parent":"88434a88a1965e4acf6bf489a7919df0d646d8e91a442ca817e371f78b95a67d",
    "created":"2015-02-11T15:51:22.129586647Z","container":"01ee15edd65ba42c68ef40d8464ae9e1e4e2867af5d131ed40e0b8acc6184100","container_config":
    {"Hostname":"4338b33adb2a","Domainname":"","User":"","Memory":0,"MemorySwap":0,"CpuShares":0,"Cpuset":"","AttachStdin":false,"AttachStdout":false,
    "AttachStderr":false,"PortSpecs":null,"ExposedPorts":{"9000/tcp":{}},"Tty":false,"OpenStdin":false,"StdinOnce":false,
    "Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
    "RUNNERVER=sonar-runner-dist-2.4","MYSQL_SERVER=localhost","MYSQL_PASS=PAssw0rd","MYSQL_DB=sonar","APP_USER=admin","APP_PASS=Passw0rd"],
    "Cmd":["/bin/sh","-c","#(nop) EXPOSE map[9000/tcp:{}]"],"Image":"88434a88a1965e4acf6bf489a7919df0d646d8e91a442ca817e371f78b95a67d","Volumes":null,"WorkingDir":"",
    "Entrypoint":null,"NetworkDisabled":false,"MacAddress":"","OnBuild":[]},"docker_version":"1.4.1","author":"Rich Nason rnason@appcontainers.com","config":
    {"Hostname":"4338b33adb2a","Domainname":"","User":"","Memory":0,"MemorySwap":0,"CpuShares":0,"Cpuset":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,
    "PortSpecs":null,"ExposedPorts":{"9000/tcp":{}},"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
    "RUNNERVER=sonar-runner-dist-2.4","MYSQL_SERVER=localhost","MYSQL_PASS=PAssw0rd","MYSQL_DB=sonar","APP_USER=admin","APP_PASS=Passw0rd"],
    "Cmd":["/bin/sh","-c","/bin/bash"],"Image":"88434a88a1965e4acf6bf489a7919df0d646d8e91a442ca817e371f78b95a67d","Volumes":null,"WorkingDir":"",
    "Entrypoint":null,"NetworkDisabled":false,"MacAddress":"","OnBuild":[]},"architecture":"amd64","os":"linux","checksum":
    "tarsum.dev+sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","Size":0}

    Summary

    So as you can see getting specific Docker image information from the API is not really all that complicated or confusing once the light has been cast on the process… Trying to find this information gem however is kinda like a plot of an old Indiana Jones movie… Hope you find this information useful and happy API requesting…

    3 comments
    bittelc
    bittelc

    How would you proceed through this if your repository is private? Eg. I can't find my repo by searching for it!

    theekarlmilton
    theekarlmilton

    What application/plugin/tool are you using for making your REST calls?

    appcontainers
    appcontainers moderator

    Postman, it's a free chrome app, that can be found in the chrome store.