mirror of
https://github.com/odoo/runbot.git
synced 2025-03-15 23:45:44 +07:00
[IMP] runbot: pull docker image only when needed
When a lot of Docker images are updated at the same time, all runbot hosts will try to pull them at the same moment. With this commit, only the images marked as `always_pull` will be pulled and if one of them takes too much time to be pulled, we let the host make another loop turn before continuing the images pull. Finally, if a host uses the Docker registry, it will pull the remote image when running a step, that way the image will be pulled automatically if needed.
This commit is contained in:
parent
b60d54d4ea
commit
3ae3f6dff3
@ -166,7 +166,7 @@ def _docker_pull(image_tag):
|
||||
"""Pull a docker image from a registry.
|
||||
:param image_tag: the full image tag, including the registry host
|
||||
e.g.: `dockerhub.runbot102.odoo.com/odoo:PureNobleTest`
|
||||
:return: tuple(success, image) where success is a boolean and image a Docker image object or None in case of failure
|
||||
:return: DockerMager.result dict
|
||||
"""
|
||||
with DockerManager(image_tag) as dm:
|
||||
for chunk in dm.consume(dm.docker_client.api.pull(image_tag, stream=True)):
|
||||
|
@ -57,6 +57,7 @@ class DockerManager:
|
||||
def __exit__(self, exception_type, exception_value, exception_traceback):
|
||||
if self.log_progress:
|
||||
_logger.info('Finished in %.2fs', self.duration)
|
||||
self.result['log_progress'] = self.log_progress
|
||||
if exception_value:
|
||||
self.result['success'] = False
|
||||
_logger.warning(exception_value)
|
||||
|
@ -16,7 +16,7 @@ from psycopg2 import sql
|
||||
from psycopg2.extensions import TransactionRollbackError
|
||||
|
||||
from ..common import dt2time, now, grep, local_pgadmin_cursor, s2human, dest_reg, os, list_local_dbs, pseudo_markdown, RunbotException, findall, sanitize, markdown_escape
|
||||
from ..container import docker_stop, docker_state, Command, docker_run
|
||||
from ..container import docker_stop, docker_state, Command, docker_run, docker_pull
|
||||
from ..fields import JsonDictField
|
||||
|
||||
from odoo import models, fields, api
|
||||
@ -853,6 +853,15 @@ class BuildResult(models.Model):
|
||||
if 'image_tag' not in kwargs:
|
||||
kwargs.update({'image_tag': self.params_id.dockerfile_id.image_tag})
|
||||
self._log('Preparing', 'Using Dockerfile Tag [%s](/runbot/dockerfile/tag/%s)', kwargs['image_tag'], kwargs['image_tag'], log_type='markdown')
|
||||
icp = self.env['ir.config_parameter']
|
||||
docker_registry_host = self.env['runbot.host'].browse(int(icp.get_param('runbot.docker_registry_host_id', default=0)))
|
||||
if docker_registry_host and self.host_id.use_remote_docker_registry:
|
||||
result = docker_pull(f"dockerhub.{docker_registry_host.name}/{kwargs['image_tag']}")
|
||||
if result['success']:
|
||||
result['image'].tag(kwargs['image_tag'])
|
||||
if result.get('log_progress'):
|
||||
self._log('Docker Run', f'Docker image was pulled {"" if result["success"] else "with errors"}')
|
||||
|
||||
containers_memory_limit = self.env['ir.config_parameter'].sudo().get_param('runbot.runbot_containers_memory', 0)
|
||||
if containers_memory_limit and 'memory' not in kwargs:
|
||||
kwargs['memory'] = int(float(containers_memory_limit) * 1024 ** 3)
|
||||
|
@ -128,6 +128,7 @@ class Dockerfile(models.Model):
|
||||
arch_base = fields.Text(related='template_id.arch_base', readonly=False, related_sudo=True)
|
||||
dockerfile = fields.Text(compute='_compute_dockerfile', tracking=True)
|
||||
to_build = fields.Boolean('To Build', help='Build Dockerfile. Check this when the Dockerfile is ready.', default=False)
|
||||
always_pull = fields.Boolean('Always pull', help='Always Pull on the hosts, not only at the use time', default=False, tracking=True)
|
||||
version_ids = fields.One2many('runbot.version', 'dockerfile_id', string='Versions')
|
||||
description = fields.Text('Description')
|
||||
view_ids = fields.Many2many('ir.ui.view', compute='_compute_view_ids', groups="runbot.group_runbot_admin")
|
||||
|
@ -130,11 +130,16 @@ class Host(models.Model):
|
||||
all_tags = set(all_docker_files.mapped('image_tag'))
|
||||
if docker_registry_host and self.use_remote_docker_registry and not is_registry:
|
||||
_logger.info('Pulling docker images...')
|
||||
for dockerfile in all_docker_files:
|
||||
total_duration = 0
|
||||
for dockerfile in all_docker_files.filtered('always_pull'):
|
||||
remote_tag = f'dockerhub.{docker_registry_host.name}/{dockerfile.image_tag}'
|
||||
result = docker_pull(remote_tag)
|
||||
if result['success']:
|
||||
result['image'].tag(dockerfile.image_tag)
|
||||
total_duration += result['duration']
|
||||
if total_duration > 60:
|
||||
_logger.warning("Pulling images took more than 60 seconds... will continue later")
|
||||
break
|
||||
else:
|
||||
_logger.info('Building docker images...')
|
||||
for dockerfile in self.env['runbot.dockerfile'].search([('to_build', '=', True)]):
|
||||
|
@ -13,6 +13,7 @@
|
||||
<field name="name"/>
|
||||
<field name="image_tag"/>
|
||||
<field name="to_build"/>
|
||||
<field name="always_pull"/>
|
||||
<field name="version_ids" widget="many2many_tags"/>
|
||||
<field name="project_ids" widget="many2many_tags"/>
|
||||
<field name="template_id"/>
|
||||
@ -104,6 +105,8 @@
|
||||
<field name="image_tag"/>
|
||||
<field name="to_build" groups="!runbot.group_runbot_admin"/>
|
||||
<field name="to_build" widget="boolean_toggle" groups="runbot.group_runbot_admin"/>
|
||||
<field name="always_pull" groups="!runbot.group_runbot_admin"/>
|
||||
<field name="always_pull" widget="boolean_toggle" groups="runbot.group_runbot_admin"/>
|
||||
<field name="version_ids" widget="many2many_tags"/>
|
||||
<field name="project_ids" widget="many2many_tags"/>
|
||||
<field name="use_count"/>
|
||||
|
Loading…
Reference in New Issue
Block a user