Skip to content

Instantly share code, notes, and snippets.

@sescobb27
Last active September 11, 2018 21:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save sescobb27/1fd9df2badcd37eb4275dab41095cfa0 to your computer and use it in GitHub Desktop.
Save sescobb27/1fd9df2badcd37eb4275dab41095cfa0 to your computer and use it in GitHub Desktop.
defmodule DockerApi do
@version "v1.37"
@endpoint URI.encode_www_form("/var/run/docker.sock")
@protocol "http+unix"
def commit(container_id, payload) do
# commit image
{:ok, %{body: body}} =
HTTPoison.post(
"#{@protocol}://#{@endpoint}/#{@version}/commit?container=#{container_id}",
Poison.encode!(payload),
[{"Content-Type", "application/json"}]
)
%{"Id" => image_id} = Poison.decode!(body)
image_id
end
def create_container(payload, name) do
{:ok, %{body: body}} =
HTTPoison.post(
"#{@protocol}://#{@endpoint}/#{@version}/containers/create?name=#{name}",
Poison.encode!(payload),
[{"Content-Type", "application/json"}]
)
%{"Id" => container_id} = Poison.decode!(body)
container_id
end
def start_container(container_id) do
{:ok, _} =
HTTPoison.post(
"#{@protocol}://#{@endpoint}/#{@version}/containers/#{container_id}/start",
"",
[
{"Content-Type", "application/json"}
]
)
container_id
end
def wait_container(container_id) do
{:ok, _} =
HTTPoison.post(
"#{@protocol}://#{@endpoint}/#{@version}/containers/#{container_id}/wait",
"",
[],
timeout: :infinity,
recv_timeout: :infinity
)
container_id
end
def upload_file(container_id, input_path, output_path) do
final_path = DockerApi.Tar.tar(input_path, File.cwd!())
archive_payload = File.read!(final_path)
{:ok, _} =
HTTPoison.put(
"#{@protocol}://#{@endpoint}/#{@version}/containers/#{container_id}/archive?path=#{
output_path
}",
archive_payload,
[{"Content-Type", "application/tar"}]
)
:ok
end
def pull(image) do
{:ok, _} =
HTTPoison.post(
"#{@protocol}://#{@endpoint}/#{@version}/images/create?fromImage=#{image}",
"",
[]
)
end
def create_volume(payload) do
{:ok, _} =
HTTPoison.post(
"#{@protocol}://#{@endpoint}/#{@version}/volumes/create",
Poison.encode!(payload),
[{"Content-Type", "application/json"}]
)
:ok
end
end
# based on https://github.com/sescobb27/elixir-docker-guide/blob/master/Dockerfile
container_id =
DockerApi.create_container(%{"Image" => "elixir:1.7.3"}, "docker-elixir-test")
|> DockerApi.start_container()
image_id = DockerApi.commit(container_id, %{})
container_id =
DockerApi.create_container(
%{"Image" => image_id, "Cmd" => ["mkdir", "/opt/app"]},
"docker-elixir-test-1"
)
|> DockerApi.start_container()
|> DockerApi.wait_container()
image_id = DockerApi.commit(container_id, %{})
container_id =
DockerApi.create_container(
%{"Image" => image_id, "Cmd" => ["mix", "local.hex", "--force"], "WorkingDir" => "/opt/app"},
"docker-elixir-test-2"
)
|> DockerApi.start_container()
|> DockerApi.wait_container()
image_id = DockerApi.commit(container_id, %{})
container_id =
DockerApi.create_container(
%{
"Image" => image_id,
"Cmd" => ["mix", "local.rebar", "--force"],
"WorkingDir" => "/opt/app"
},
"docker-elixir-test-3"
)
|> DockerApi.start_container()
|> DockerApi.wait_container()
DockerApi.upload_file(
container_id,
"/Users/kiro/workspace/elixir/elixir-docker-guide",
"/opt/app"
)
image_id = DockerApi.commit(container_id, %{})
container_id =
DockerApi.create_container(
%{
"Image" => image_id,
"Cmd" => ["mix", "deps.get", "--only", "prod"],
"WorkingDir" => "/opt/app"
},
"docker-elixir-test-4"
)
|> DockerApi.start_container()
|> DockerApi.wait_container()
image_id = DockerApi.commit(container_id, %{})
container_id =
DockerApi.create_container(
%{
"Image" => image_id,
"Cmd" => ["mix", "release"],
"WorkingDir" => "/opt/app",
"Env" => ["MIX_ENV=prod"]
},
"docker-elixir-test-5"
) |> DockerApi.start_container() |> DockerApi.wait_container()
image_id = DockerApi.commit(container_id, %{
"Image" => image_id,
"Entrypoint" => ["_build/prod/rel/clock/bin/clock"],
"Cmd" => ["foreground"],
"WorkingDir" => "/opt/app"
})
@sescobb27
Copy link
Author

sescobb27 commented Sep 11, 2018

adding support for VOLUMES and bind-mounts seems really straightforward

# VOLUMES
container_id =
  DockerApi.create_container(
    %{
      "Image" => image_id,
      "Volumes" => %{
        "/data" => %{},
        "/db/data" => %{}
        # etc
      },
      "HostConfig" => %{
        "Binds" => [
          "/Users/kiro/workspace/elixir/elixir-docker-guide:/source"
          # same as docker build
        ]
      }
    },
    "docker-elixir-test-volumes"
  ) |> DockerApi.start_container() |> DockerApi.wait_container()

image_id = DockerApi.commit(container_id, %{})

Result

screen shot 2018-09-11 at 4 10 54 pm

@sescobb27
Copy link
Author

sescobb27 commented Sep 11, 2018

there is also a VolumeCreate for creating non anonymous Volumes so container can share them

# create volume
DockerApi.create_volume(%{"Name" => "log_storage"}

# bind a container to a volume
container_id =
  DockerApi.create_container(
    %{
      "Image" => image_id,
      "HostConfig" => %{
        "Binds" => [
          "log_storage:/source"
        ]
      }
    },
    "docker-elixir-test-volumes"
  ) |> DockerApi.start_container() |> DockerApi.wait_container()

image_id = DockerApi.commit(container_id, %{})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment