Class: Docker::Image

Inherits:
Object
  • Object
show all
Includes:
Base
Defined in:
lib/docker/image.rb

Overview

This class represents a Docker Image.

Instance Attribute Summary

Attributes included from Base

#connection, #id, #info

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Base

#initialize, #normalize_hash

Class Method Details

.all(opts = {}, conn = Docker.connection) ⇒ Object

Return every Image.



219
220
221
222
# File 'lib/docker/image.rb', line 219

def all(opts = {}, conn = Docker.connection)
  hashes = Docker::Util.parse_json(conn.get('/images/json', opts)) || []
  hashes.map { |hash| new(conn, hash) }
end

.build(commands, opts = {}, connection = Docker.connection, &block) ⇒ Object

Given a Dockerfile as a string, builds an Image.



271
272
273
274
275
276
277
278
279
280
281
# File 'lib/docker/image.rb', line 271

def build(commands, opts = {}, connection = Docker.connection, &block)
  body = +""
  connection.post(
    '/build', opts,
    :body => Docker::Util.create_tar('Dockerfile' => commands),
    :response_block => response_block(body, &block)
  )
  new(connection, 'id' => Docker::Util.extract_id(body))
rescue Docker::Error::ServerError
  raise Docker::Error::UnexpectedResponseError
end

.build_from_dir(dir, opts = {}, connection = Docker.connection, creds = nil, &block) ⇒ Object

Given a directory that contains a Dockerfile, builds an Image.

If a block is passed, chunks of output produced by Docker will be passed to that block.



309
310
311
312
313
314
315
316
317
318
319
# File 'lib/docker/image.rb', line 309

def build_from_dir(dir, opts = {}, connection = Docker.connection,
                   creds = nil, &block)

  tar = Docker::Util.create_dir_tar(dir)
  build_from_tar tar, opts, connection, creds, &block
ensure
  unless tar.nil?
    tar.close
    FileUtils.rm(tar.path, force: true)
  end
end

.build_from_tar(tar, opts = {}, connection = Docker.connection, creds = nil, &block) ⇒ Object

Given File like object containing a tar file, builds an Image.

If a block is passed, chunks of output produced by Docker will be passed to that block.



287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
# File 'lib/docker/image.rb', line 287

def build_from_tar(tar, opts = {}, connection = Docker.connection,
                   creds = nil, &block)

  headers = build_headers(creds)

  # The response_block passed to Excon will build up this body variable.
  body = +""
  connection.post(
    '/build', opts,
    :headers => headers,
    :response_block => response_block(body, &block)
  ) { tar.read(Excon.defaults[:chunk_size]).to_s }

  new(connection,
      'id' => Docker::Util.extract_id(body),
      :headers => headers)
end

.create(opts = {}, creds = nil, conn = Docker.connection, &block) ⇒ Object

Create a new Image.



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/docker/image.rb', line 121

def create(opts = {}, creds = nil, conn = Docker.connection, &block)
  credentials = creds.nil? ? Docker.creds : MultiJson.dump(creds)
  headers = credentials && Docker::Util.build_auth_header(credentials) || {}
  body = +''
  conn.post(
    '/images/create',
    opts,
    :headers => headers,
    :response_block => response_block(body, &block)
    )
  # NOTE: see associated tests for why we're looking at image#end_with?
  image = opts['fromImage'] || opts[:fromImage]
  tag = opts['tag'] || opts[:tag]
  image = "#{image}:#{tag}" if tag && !image.end_with?(":#{tag}")
  get(image, {}, conn)
end

.exist?(id, opts = {}, conn = Docker.connection) ⇒ Boolean

Check if an image exists.

Returns:

  • (Boolean)


211
212
213
214
215
216
# File 'lib/docker/image.rb', line 211

def exist?(id, opts = {}, conn = Docker.connection)
  get(id, opts, conn)
  true
rescue Docker::Error::NotFoundError
  false
end

.get(id, opts = {}, conn = Docker.connection) ⇒ Object

Return a specific image.



139
140
141
142
143
# File 'lib/docker/image.rb', line 139

def get(id, opts = {}, conn = Docker.connection)
  image_json = conn.get("/images/#{id}/json", opts)
  hash = Docker::Util.parse_json(image_json) || {}
  new(conn, hash)
end

.import(imp, opts = {}, conn = Docker.connection) ⇒ Object

Import an Image from the output of Docker::Container#export. The first argument may either be a File or URI.



240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/docker/image.rb', line 240

def import(imp, opts = {}, conn = Docker.connection)
  require 'open-uri'

  # This differs after Ruby 2.4
  if URI.public_methods.include?(:open)
    munged_open = URI.method(:open)
  else
    munged_open = self.method(:open)
  end

  munged_open.call(imp) do |io|
    import_stream(opts, conn) do
      io.read(Excon.defaults[:chunk_size]).to_s
    end
  end
rescue StandardError
  raise Docker::Error::IOError, "Could not import '#{imp}'"
end

.import_stream(options = {}, connection = Docker.connection, &block) ⇒ Object



259
260
261
262
263
264
265
266
267
268
# File 'lib/docker/image.rb', line 259

def import_stream(options = {}, connection = Docker.connection, &block)
  body = connection.post(
    '/images/create',
     options.merge('fromSrc' => '-'),
     :headers => { 'Content-Type' => 'application/tar',
                   'Transfer-Encoding' => 'chunked' },
     &block
  )
  new(connection, 'id'=> Docker::Util.parse_json(body)['status'])
end

.load(tar, opts = {}, conn = Docker.connection, creds = nil, &block) ⇒ Object

Load a tar Image



198
199
200
201
202
203
204
205
206
207
208
# File 'lib/docker/image.rb', line 198

def load(tar, opts = {}, conn = Docker.connection, creds = nil, &block)
   headers = build_headers(creds)
   io = tar.is_a?(String) ? File.open(tar, 'rb') : tar
   body = +""
   conn.post(
     '/images/load',
     opts,
     :headers => headers,
     :response_block => response_block(body, &block)
   ) { io.read(Excon.defaults[:chunk_size]).to_s }
end

.prune(conn = Docker.connection) ⇒ Object

Prune images



152
153
154
# File 'lib/docker/image.rb', line 152

def prune(conn = Docker.connection)
  conn.post("/images/prune", {})
end

.remove(id, opts = {}, conn = Docker.connection) ⇒ Object Also known as: delete

Delete a specific image



146
147
148
# File 'lib/docker/image.rb', line 146

def remove(id, opts = {}, conn = Docker.connection)
  conn.delete("/images/#{id}", opts)
end

.save(names, filename = nil, conn = Docker.connection) ⇒ NilClass, String

Save the raw binary representation or one or more Docker images

representation of the binary data. If the filename is not nil, then return nil.

Parameters:

  • names (String, Array#String)

    The image(s) you wish to save

  • filename (String) (defaults to: nil)

    The file to export the data to.

  • conn (Docker::Connection) (defaults to: Docker.connection)

    The Docker connection to use

Returns:

  • (NilClass, String)

    If filename is nil, return the string



166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/docker/image.rb', line 166

def save(names, filename = nil, conn = Docker.connection)
  if filename
    File.open(filename, 'wb') do |file|
      save_stream(names, {}, conn, &response_block_for_save(file))
    end
    nil
  else
    string = +''
    save_stream(names, {}, conn, &response_block_for_save(string))
    string
  end
end

.save_stream(names, opts = {}, conn = Docker.connection, &block) ⇒ Object

Stream the contents of Docker image(s) to a block.

Parameters:

  • names (String, Array#String)

    The image(s) you wish to save

  • conn (Docker::Connection) (defaults to: Docker.connection)

    The Docker connection to use



184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/docker/image.rb', line 184

def save_stream(names, opts = {}, conn = Docker.connection, &block)
  # By using compare_by_identity we can create a Hash that has
  # the same key multiple times.
  query = {}.tap(&:compare_by_identity)
  Array(names).each { |name| query['names'.dup] = name }
  conn.get(
    '/images/get',
    query,
    opts.merge(:response_block => block)
  )
  nil
end

.search(query = {}, connection = Docker.connection, creds = nil) ⇒ Object

Given a query like ‘{ :term => ’sshd’ }‘, queries the Docker Registry for a corresponding Image.



226
227
228
229
230
231
232
233
234
235
236
# File 'lib/docker/image.rb', line 226

def search(query = {}, connection = Docker.connection, creds = nil)
  credentials = creds.nil? ? Docker.creds : creds.to_json
  headers = credentials && Docker::Util.build_auth_header(credentials) || {}
  body = connection.get(
    '/images/search',
    query,
    :headers => headers,
  )
  hashes = Docker::Util.parse_json(body) || []
  hashes.map { |hash| new(connection, 'id' => hash['name']) }
end

Instance Method Details

#deleteObject

Remove the Image from the server.



82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/docker/image.rb', line 82

def remove(opts = {})
  name = opts.delete(:name)

  unless name
    if ::Docker.podman?(connection)
      name = self.id.split(':').last
    else
      name = self.id
    end
  end

  connection.delete("/images/#{name}", opts)
end

#insert_local(opts = {}) ⇒ Object

Given a path of a local file and the path it should be inserted, creates a new Image that has that file.



53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/docker/image.rb', line 53

def insert_local(opts = {})
  local_paths = opts.delete('localPath')
  output_path = opts.delete('outputPath')

  local_paths = [ local_paths ] unless local_paths.is_a?(Array)

  file_hash = Docker::Util.file_hash_from_paths(local_paths)

  file_hash['Dockerfile'] = dockerfile_for(file_hash, output_path)

  tar = Docker::Util.create_tar(file_hash)
  body = connection.post('/build', opts, :body => tar)
  self.class.send(:new, connection, 'id' => Docker::Util.extract_id(body))
end

#push(creds = nil, options = {}, &block) ⇒ Object

Push the Image to the Docker registry.

Raises:



27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/docker/image.rb', line 27

def push(creds = nil, options = {}, &block)
  repo_tag = options.delete(:repo_tag) || ensure_repo_tags.first
  raise ArgumentError, "Image is untagged" if repo_tag.nil?
  repo, tag = Docker::Util.parse_repo_tag(repo_tag)
  raise ArgumentError, "Image does not have a name to push." if repo.nil?

  body = +""
  credentials = creds || Docker.creds || {}
  headers = Docker::Util.build_auth_header(credentials)
  opts = {:tag => tag}.merge(options)
  connection.post("/images/#{repo}/push", opts, :headers => headers,
                  :response_block => self.class.response_block(body, &block))
  self
end

#refresh!Object

Update the @info hash, which is the only mutable state in this object.



109
110
111
112
113
114
115
116
# File 'lib/docker/image.rb', line 109

def refresh!
  img = Docker::Image.all({:all => true}, connection).find { |image|
    image.id.start_with?(self.id) || self.id.start_with?(image.id)
  }
  info.merge!(self.json)
  img && info.merge!(img.info)
  self
end

#remove(opts = {}) ⇒ Object

Remove the Image from the server.



69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/docker/image.rb', line 69

def remove(opts = {})
  name = opts.delete(:name)

  unless name
    if ::Docker.podman?(connection)
      name = self.id.split(':').last
    else
      name = self.id
    end
  end

  connection.delete("/images/#{name}", opts)
end

#run(cmd = nil, options = {}) ⇒ Object

Given a command and optional list of streams to attach to, run a command on an Image. This will not modify the Image, but rather create a new Container to run the Image. If the image has an embedded config, no command is necessary, but it will fail with 500 if no config is saved with the image



11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/docker/image.rb', line 11

def run(cmd = nil, options = {})
  opts = {'Image' => self.id}.merge(options)
  opts["Cmd"] = cmd.is_a?(String) ? cmd.split(/\s+/) : cmd
  begin
    Docker::Container.create(opts, connection)
                     .tap(&:start!)
  rescue ServerError, ClientError => ex
    if cmd
      raise ex
    else
      raise ex, "No command specified."
    end
  end
end

#save(filename = nil) ⇒ Object

Save the image as a tarball



99
100
101
# File 'lib/docker/image.rb', line 99

def save(filename = nil)
  self.class.save(self.id, filename, connection)
end

#save_stream(opts = {}, &block) ⇒ Object

Save the image as a tarball to an IO object.



104
105
106
# File 'lib/docker/image.rb', line 104

def save_stream(opts = {}, &block)
  self.class.save_stream(self.id, opts, connection, &block)
end

#tag(opts = {}) ⇒ Object

Tag the Image.



43
44
45
46
47
48
49
# File 'lib/docker/image.rb', line 43

def tag(opts = {})
  self.info['RepoTags'] ||= []
  connection.post(path_for(:tag), opts)
  repo = opts['repo'] || opts[:repo]
  tag = opts['tag'] || opts[:tag] || 'latest'
  self.info['RepoTags'] << "#{repo}:#{tag}"
end

#to_sObject

Return a String representation of the Image.



85
86
87
88
# File 'lib/docker/image.rb', line 85

def to_s
  "Docker::Image { :id => #{self.id}, :info => #{self.info.inspect}, "\
    ":connection => #{self.connection} }"
end