<!doctype html>
< html lang = "en" class = "no-js" >
< head >
< meta charset = "utf-8" >
< meta name = "viewport" content = "width=device-width,initial-scale=1" >
< link rel = "canonical" href = "https://containrrr.dev/watchtower/private-registries/" >
< link rel = "prev" href = "../container-selection/" >
< link rel = "next" href = "../linked-containers/" >
< link rel = "icon" href = "../images/favicon.ico" >
< meta name = "generator" content = "mkdocs-1.5.3, mkdocs-material-9.4.8" >
< title > Private registries - Watchtower< / title >
< link rel = "stylesheet" href = "../assets/stylesheets/main.4b4a2bd9.min.css" >
< link rel = "stylesheet" href = "../assets/stylesheets/palette.356b1318.min.css" >
< link rel = "preconnect" href = "https://fonts.gstatic.com" crossorigin >
< link rel = "stylesheet" href = "https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback" >
< style > : root { --md-text-font : "Roboto" ; --md-code-font : "Roboto Mono" } < / style >
< link rel = "stylesheet" href = "../stylesheets/theme.css" >
< script > _ _md _scope = new URL ( ".." , location ) , _ _md _hash = e => [ ... e ] . reduce ( ( e , _ ) => ( e << 5 ) - e + _ . charCodeAt ( 0 ) , 0 ) , _ _md _get = ( e , _ = localStorage , t = _ _md _scope ) => JSON . parse ( _ . getItem ( t . pathname + "." + e ) ) , _ _md _set = ( e , _ , t = localStorage , a = _ _md _scope ) => { try { t . setItem ( a . pathname + "." + e , JSON . stringify ( _ ) ) } catch ( e ) { } } < / script >
< / head >
< body dir = "ltr" data-md-color-scheme = "containrrr" data-md-color-primary = "indigo" data-md-color-accent = "indigo" >
< script > var palette = _ _md _get ( "__palette" ) ; if ( palette && "object" == typeof palette . color ) for ( var key of Object . keys ( palette . color ) ) document . body . setAttribute ( "data-md-color-" + key , palette . color [ key ] ) < / script >
< input class = "md-toggle" data-md-toggle = "drawer" type = "checkbox" id = "__drawer" autocomplete = "off" >
< input class = "md-toggle" data-md-toggle = "search" type = "checkbox" id = "__search" autocomplete = "off" >
< label class = "md-overlay" for = "__drawer" > < / label >
< div data-md-component = "skip" >
< a href = "#create_the_configuration_file_manually" class = "md-skip" >
Skip to content
< / a >
< / div >
< div data-md-component = "announce" >
< / div >
< header class = "md-header md-header--shadow" data-md-component = "header" >
< nav class = "md-header__inner md-grid" aria-label = "Header" >
< a href = ".." title = "Watchtower" class = "md-header__button md-logo" aria-label = "Watchtower" data-md-component = "logo" >
< img src = "../images/logo-450px.png" alt = "logo" >
< / a >
< label class = "md-header__button md-icon" for = "__drawer" >
< svg xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 24 24" > < path d = "M3 6h18v2H3V6m0 5h18v2H3v-2m0 5h18v2H3v-2Z" / > < / svg >
< / label >
< div class = "md-header__title" data-md-component = "header-title" >
< div class = "md-header__ellipsis" >
< div class = "md-header__topic" >
< span class = "md-ellipsis" >
Watchtower
< / span >
< / div >
< div class = "md-header__topic" data-md-component = "header-topic" >
< span class = "md-ellipsis" >
Private registries
< / span >
< / div >
< / div >
< / div >
< form class = "md-header__option" data-md-component = "palette" >
< input class = "md-option" data-md-color-media = "(prefers-color-scheme: light)" data-md-color-scheme = "containrrr" data-md-color-primary = "indigo" data-md-color-accent = "indigo" aria-label = "Switch to dark mode" type = "radio" name = "__palette" id = "__palette_1" >
< label class = "md-header__button md-icon" title = "Switch to dark mode" for = "__palette_2" hidden >
< svg xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 24 24" > < path d = "m17.75 4.09-2.53 1.94.91 3.06-2.63-1.81-2.63 1.81.91-3.06-2.53-1.94L12.44 4l1.06-3 1.06 3 3.19.09m3.5 6.91-1.64 1.25.59 1.98-1.7-1.17-1.7 1.17.59-1.98L15.75 11l2.06-.05L18.5 9l.69 1.95 2.06.05m-2.28 4.95c.83-.08 1.72 1.1 1.19 1.85-.32.45-.66.87-1.08 1.27C15.17 23 8.84 23 4.94 19.07c-3.91-3.9-3.91-10.24 0-14.14.4-.4.82-.76 1.27-1.08.75-.53 1.93.36 1.85 1.19-.27 2.86.69 5.83 2.89 8.02a9.96 9.96 0 0 0 8.02 2.89m-1.64 2.02a12.08 12.08 0 0 1-7.8-3.47c-2.17-2.19-3.33-5-3.49-7.82-2.81 3.14-2.7 7.96.31 10.98 3.02 3.01 7.84 3.12 10.98.31Z" / > < / svg >
< / label >
< input class = "md-option" data-md-color-media = "(prefers-color-scheme: dark)" data-md-color-scheme = "containrrr-dark" data-md-color-primary = "indigo" data-md-color-accent = "indigo" aria-label = "Switch to light mode" type = "radio" name = "__palette" id = "__palette_2" >
< label class = "md-header__button md-icon" title = "Switch to light mode" for = "__palette_1" hidden >
< svg xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 24 24" > < path d = "M12 7a5 5 0 0 1 5 5 5 5 0 0 1-5 5 5 5 0 0 1-5-5 5 5 0 0 1 5-5m0 2a3 3 0 0 0-3 3 3 3 0 0 0 3 3 3 3 0 0 0 3-3 3 3 0 0 0-3-3m0-7 2.39 3.42C13.65 5.15 12.84 5 12 5c-.84 0-1.65.15-2.39.42L12 2M3.34 7l4.16-.35A7.2 7.2 0 0 0 5.94 8.5c-.44.74-.69 1.5-.83 2.29L3.34 7m.02 10 1.76-3.77a7.131 7.131 0 0 0 2.38 4.14L3.36 17M20.65 7l-1.77 3.79a7.023 7.023 0 0 0-2.38-4.15l4.15.36m-.01 10-4.14.36c.59-.51 1.12-1.14 1.54-1.86.42-.73.69-1.5.83-2.29L20.64 17M12 22l-2.41-3.44c.74.27 1.55.44 2.41.44.82 0 1.63-.17 2.37-.44L12 22Z" / > < / svg >
< / label >
< / form >
< label class = "md-header__button md-icon" for = "__search" >
< svg xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 24 24" > < path d = "M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z" / > < / svg >
< / label >
< div class = "md-search" data-md-component = "search" role = "dialog" >
< label class = "md-search__overlay" for = "__search" > < / label >
< div class = "md-search__inner" role = "search" >
< form class = "md-search__form" name = "search" >
< input type = "text" class = "md-search__input" name = "query" aria-label = "Search" placeholder = "Search" autocapitalize = "off" autocorrect = "off" autocomplete = "off" spellcheck = "false" data-md-component = "search-query" required >
< label class = "md-search__icon md-icon" for = "__search" >
< svg xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 24 24" > < path d = "M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z" / > < / svg >
< svg xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 24 24" > < path d = "M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12Z" / > < / svg >
< / label >
< nav class = "md-search__options" aria-label = "Search" >
< button type = "reset" class = "md-search__icon md-icon" title = "Clear" aria-label = "Clear" tabindex = "-1" >
< svg xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 24 24" > < path d = "M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41Z" / > < / svg >
< / button >
< / nav >
< / form >
< div class = "md-search__output" >
< div class = "md-search__scrollwrap" data-md-scrollfix >
< div class = "md-search-result" data-md-component = "search-result" >
< div class = "md-search-result__meta" >
Initializing search
< / div >
< ol class = "md-search-result__list" role = "presentation" > < / ol >
< / div >
< / div >
< / div >
< / div >
< / div >
< div class = "md-header__source" >
< a href = "https://github.com/containrrr/watchtower/" title = "Go to repository" class = "md-source" data-md-component = "source" >
< div class = "md-source__icon md-icon" >
< svg xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 448 512" > <!-- ! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. --> < path d = "M439.55 236.05 244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z" / > < / svg >
< / div >
< div class = "md-source__repository" >
GitHub
< / div >
< / a >
< / div >
< / nav >
< / header >
< div class = "md-container" data-md-component = "container" >
< main class = "md-main" data-md-component = "main" >
< div class = "md-main__inner md-grid" >
< div class = "md-sidebar md-sidebar--primary" data-md-component = "sidebar" data-md-type = "navigation" >
< div class = "md-sidebar__scrollwrap" >
< div class = "md-sidebar__inner" >
< nav class = "md-nav md-nav--primary" aria-label = "Navigation" data-md-level = "0" >
< label class = "md-nav__title" for = "__drawer" >
< a href = ".." title = "Watchtower" class = "md-nav__button md-logo" aria-label = "Watchtower" data-md-component = "logo" >
< img src = "../images/logo-450px.png" alt = "logo" >
< / a >
Watchtower
< / label >
< div class = "md-nav__source" >
< a href = "https://github.com/containrrr/watchtower/" title = "Go to repository" class = "md-source" data-md-component = "source" >
< div class = "md-source__icon md-icon" >
< svg xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 448 512" > <!-- ! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. --> < path d = "M439.55 236.05 244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z" / > < / svg >
< / div >
< div class = "md-source__repository" >
GitHub
< / div >
< / a >
< / div >
< ul class = "md-nav__list" data-md-scrollfix >
< li class = "md-nav__item" >
< a href = ".." class = "md-nav__link" >
< span class = "md-ellipsis" >
Home
< / span >
< / a >
< / li >
< li class = "md-nav__item" >
< a href = "../introduction/" class = "md-nav__link" >
< span class = "md-ellipsis" >
Introduction
< / span >
< / a >
< / li >
< li class = "md-nav__item" >
< a href = "../usage-overview/" class = "md-nav__link" >
< span class = "md-ellipsis" >
Usage overview
< / span >
< / a >
< / li >
< li class = "md-nav__item" >
< a href = "../arguments/" class = "md-nav__link" >
< span class = "md-ellipsis" >
Arguments
< / span >
< / a >
< / li >
< li class = "md-nav__item" >
< a href = "../notifications/" class = "md-nav__link" >
< span class = "md-ellipsis" >
Notifications
< / span >
< / a >
< / li >
< li class = "md-nav__item" >
< a href = "../container-selection/" class = "md-nav__link" >
< span class = "md-ellipsis" >
Container selection
< / span >
< / a >
< / li >
< li class = "md-nav__item md-nav__item--active" >
< input class = "md-nav__toggle md-toggle" type = "checkbox" id = "__toc" >
< label class = "md-nav__link md-nav__link--active" for = "__toc" >
< span class = "md-ellipsis" >
Private registries
< / span >
< span class = "md-nav__icon md-icon" > < / span >
< / label >
< a href = "./" class = "md-nav__link md-nav__link--active" >
< span class = "md-ellipsis" >
Private registries
< / span >
< / a >
< nav class = "md-nav md-nav--secondary" aria-label = "Table of contents" >
< label class = "md-nav__title" for = "__toc" >
< span class = "md-nav__icon md-icon" > < / span >
Table of contents
< / label >
< ul class = "md-nav__list" data-md-component = "toc" data-md-scrollfix >
< li class = "md-nav__item" >
< a href = "#create_the_configuration_file_manually" class = "md-nav__link" >
Create the configuration file manually
< / a >
< / li >
< li class = "md-nav__item" >
< a href = "#share_the_docker_configuration_file" class = "md-nav__link" >
Share the Docker configuration file
< / a >
< nav class = "md-nav" aria-label = "Share the Docker configuration file" >
< ul class = "md-nav__list" >
< li class = "md-nav__item" >
< a href = "#docker_config_path" class = "md-nav__link" >
Docker Config path
< / a >
< / li >
< / ul >
< / nav >
< / li >
< li class = "md-nav__item" >
< a href = "#credential_helpers" class = "md-nav__link" >
Credential helpers
< / a >
< nav class = "md-nav" aria-label = "Credential helpers" >
< ul class = "md-nav__list" >
< li class = "md-nav__item" >
< a href = "#example" class = "md-nav__link" >
Example
< / a >
< / li >
< / ul >
< / nav >
< / li >
< / ul >
< / nav >
< / li >
< li class = "md-nav__item" >
< a href = "../linked-containers/" class = "md-nav__link" >
< span class = "md-ellipsis" >
Linked containers
< / span >
< / a >
< / li >
< li class = "md-nav__item" >
< a href = "../remote-hosts/" class = "md-nav__link" >
< span class = "md-ellipsis" >
Remote hosts
< / span >
< / a >
< / li >
< li class = "md-nav__item" >
< a href = "../secure-connections/" class = "md-nav__link" >
< span class = "md-ellipsis" >
Secure connections
< / span >
< / a >
< / li >
< li class = "md-nav__item" >
< a href = "../stop-signals/" class = "md-nav__link" >
< span class = "md-ellipsis" >
Stop signals
< / span >
< / a >
< / li >
< li class = "md-nav__item" >
< a href = "../lifecycle-hooks/" class = "md-nav__link" >
< span class = "md-ellipsis" >
Lifecycle hooks
< / span >
< / a >
< / li >
< li class = "md-nav__item" >
< a href = "../running-multiple-instances/" class = "md-nav__link" >
< span class = "md-ellipsis" >
Running multiple instances
< / span >
< / a >
< / li >
< li class = "md-nav__item" >
< a href = "../http-api-mode/" class = "md-nav__link" >
< span class = "md-ellipsis" >
HTTP API Mode
< / span >
< / a >
< / li >
< li class = "md-nav__item" >
< a href = "../metrics/" class = "md-nav__link" >
< span class = "md-ellipsis" >
Metrics
< / span >
< / a >
< / li >
< / ul >
< / nav >
< / div >
< / div >
< / div >
< div class = "md-sidebar md-sidebar--secondary" data-md-component = "sidebar" data-md-type = "toc" >
< div class = "md-sidebar__scrollwrap" >
< div class = "md-sidebar__inner" >
< nav class = "md-nav md-nav--secondary" aria-label = "Table of contents" >
< label class = "md-nav__title" for = "__toc" >
< span class = "md-nav__icon md-icon" > < / span >
Table of contents
< / label >
< ul class = "md-nav__list" data-md-component = "toc" data-md-scrollfix >
< li class = "md-nav__item" >
< a href = "#create_the_configuration_file_manually" class = "md-nav__link" >
Create the configuration file manually
< / a >
< / li >
< li class = "md-nav__item" >
< a href = "#share_the_docker_configuration_file" class = "md-nav__link" >
Share the Docker configuration file
< / a >
< nav class = "md-nav" aria-label = "Share the Docker configuration file" >
< ul class = "md-nav__list" >
< li class = "md-nav__item" >
< a href = "#docker_config_path" class = "md-nav__link" >
Docker Config path
< / a >
< / li >
< / ul >
< / nav >
< / li >
< li class = "md-nav__item" >
< a href = "#credential_helpers" class = "md-nav__link" >
Credential helpers
< / a >
< nav class = "md-nav" aria-label = "Credential helpers" >
< ul class = "md-nav__list" >
< li class = "md-nav__item" >
< a href = "#example" class = "md-nav__link" >
Example
< / a >
< / li >
< / ul >
< / nav >
< / li >
< / ul >
< / nav >
< / div >
< / div >
< / div >
< div class = "md-content" data-md-component = "content" >
< article class = "md-content__inner md-typeset" >
< h1 > Private registries< / h1 >
< p > Watchtower supports private Docker image registries. In many cases, accessing a private registry
requires a valid username and password (i.e., < em > credentials< / em > ). In order to operate in such an
environment, watchtower needs to know the credentials to access the registry. < / p >
< p > The credentials can be provided to watchtower in a configuration file called < code > config.json< / code > .
There are two ways to generate this configuration file:< / p >
< ul >
< li > The configuration file can be created manually.< / li >
< li > Call < code > docker login < REGISTRY_NAME> < / code > and share the resulting configuration file.< / li >
< / ul >
< h3 id = "create_the_configuration_file_manually" > Create the configuration file manually< a class = "headerlink" href = "#create_the_configuration_file_manually" title = "Permanent link" > ¶ < / a > < / h3 >
< p > Create a new configuration file with the following syntax and a base64 encoded username and
password < code > auth< / code > string:< / p >
< div class = "highlight" > < pre > < span > < / span > < code > < span class = "p" > {< / span >
< span class = "w" > < / span > < span class = "nt" > " auths" < / span > < span class = "p" > :< / span > < span class = "w" > < / span > < span class = "p" > {< / span >
< span class = "w" > < / span > < span class = "nt" > " < REGISTRY_NAME> " < / span > < span class = "p" > :< / span > < span class = "w" > < / span > < span class = "p" > {< / span >
< span class = "w" > < / span > < span class = "nt" > " auth" < / span > < span class = "p" > :< / span > < span class = "w" > < / span > < span class = "s2" > " XXXXXXX" < / span >
< span class = "w" > < / span > < span class = "p" > }< / span >
< span class = "w" > < / span > < span class = "p" > }< / span >
< span class = "p" > }< / span >
< / code > < / pre > < / div >
< p > < code > < REGISTRY_NAME> < / code > needs to be replaced by the name of your private registry
(e.g., < code > my-private-registry.example.org< / code > ).< / p >
< div class = "admonition info" >
< p class = "admonition-title" > Using private images on Docker Hub< / p >
< p > To access private repositories on Docker Hub,
< code > < REGISTRY_NAME> < / code > should be < code > https://index.docker.io/v1/< / code > .
In this special case, the registry domain does not have to be specified
in < code > docker run< / code > or < code > docker-compose< / code > . Like Docker, Watchtower will use the
Docker Hub registry and its credentials when no registry domain is specified.< / p >
< p > < sub > Watchtower will recognize credentials with < code > < REGISTRY_NAME> < / code > < code > index.docker.io< / code > ,
but the Docker CLI will not.< / sub > < / p >
< / div >
< div class = "admonition important" >
< p class = "admonition-title" > Using a private registry on a local host< / p >
< p > To use a private registry hosted locally, make sure to correctly specify the registry host
in both < code > config.json< / code > and the < code > docker run< / code > command or < code > docker-compose< / code > file.
Valid hosts are < code > localhost[:PORT]< / code > , < code > HOST:PORT< / code > ,
or any multi-part < code > domain.name< / code > or IP-address with or without a port.< / p >
< p > Examples:
* < code > localhost< / code > -> < code > localhost/myimage< / code >
* < code > 127.0.0.1< / code > -> < code > 127.0.0.1/myimage:mytag< / code >
* < code > host.domain< / code > -> < code > host.domain/myorganization/myimage< / code >
* < code > other-lan-host:80< / code > -> < code > other-lan-host:80/imagename:latest< / code > < / p >
< / div >
< p > The required < code > auth< / code > string can be generated as follows:< / p >
< div class = "highlight" > < pre > < span > < / span > < code > < span class = "nb" > echo< / span > < span class = "w" > < / span > -n< span class = "w" > < / span > < span class = "s1" > ' username:password' < / span > < span class = "w" > < / span > < span class = "p" > |< / span > < span class = "w" > < / span > base64
< / code > < / pre > < / div >
< div class = "admonition info" >
< p class = "admonition-title" > Username and Password for GCloud< / p >
< p > For gcloud, we'll use < code > _json_key< / code > as our username and the content of < code > gcloudauth.json< / code > as the password.
< div class = "highlight" > < pre > < span > < / span > < code > bash echo -n " _json_key:$(cat gcloudauth.json)" | base64 -w0
< / code > < / pre > < / div > < / p >
< / div >
< p > When the watchtower Docker container is started, the created configuration file
(< code > < PATH> /config.json< / code > in this example) needs to be passed to the container:< / p >
< div class = "highlight" > < pre > < span > < / span > < code > docker< span class = "w" > < / span > run< span class = "w" > < / span > < span class = "o" > [< / span > ...< span class = "o" > ]< / span > < span class = "w" > < / span > -v< span class = "w" > < / span > < PATH> /config.json:/config.json< span class = "w" > < / span > containrrr/watchtower
< / code > < / pre > < / div >
< h3 id = "share_the_docker_configuration_file" > Share the Docker configuration file< a class = "headerlink" href = "#share_the_docker_configuration_file" title = "Permanent link" > ¶ < / a > < / h3 >
< p > To pull an image from a private registry, < code > docker login< / code > needs to be called first, to get access
to the registry. The provided credentials are stored in a configuration file called < code > < PATH_TO_HOME_DIR> /.docker/config.json< / code > .
This configuration file can be directly used by watchtower. In this case, the creation of an
additional configuration file is not necessary.< / p >
< p > When the Docker container is started, pass the configuration file to watchtower:< / p >
< div class = "highlight" > < pre > < span > < / span > < code > docker< span class = "w" > < / span > run< span class = "w" > < / span > < span class = "o" > [< / span > ...< span class = "o" > ]< / span > < span class = "w" > < / span > -v< span class = "w" > < / span > < PATH_TO_HOME_DIR> /.docker/config.json:/config.json< span class = "w" > < / span > containrrr/watchtower
< / code > < / pre > < / div >
< p > When creating the watchtower container via docker-compose, use the following lines:< / p >
< div class = "highlight" > < pre > < span > < / span > < code > < span class = "nt" > version< / span > < span class = "p" > :< / span > < span class = "w" > < / span > < span class = "s" > " 3.4" < / span >
< span class = "nt" > services< / span > < span class = "p" > :< / span >
< span class = "w" > < / span > < span class = "nt" > watchtower< / span > < span class = "p" > :< / span >
< span class = "w" > < / span > < span class = "nt" > image< / span > < span class = "p" > :< / span > < span class = "w" > < / span > < span class = "l l-Scalar l-Scalar-Plain" > containrrr/watchtower:latest< / span >
< span class = "w" > < / span > < span class = "nt" > volumes< / span > < span class = "p" > :< / span >
< span class = "w" > < / span > < span class = "p p-Indicator" > -< / span > < span class = "w" > < / span > < span class = "l l-Scalar l-Scalar-Plain" > /var/run/docker.sock:/var/run/docker.sock< / span >
< span class = "w" > < / span > < span class = "p p-Indicator" > -< / span > < span class = "w" > < / span > < span class = "l l-Scalar l-Scalar-Plain" > < PATH_TO_HOME_DIR> /.docker/config.json:/config.json< / span >
< span class = "w" > < / span > < span class = "l l-Scalar l-Scalar-Plain" > ...< / span >
< / code > < / pre > < / div >
< h4 id = "docker_config_path" > Docker Config path< a class = "headerlink" href = "#docker_config_path" title = "Permanent link" > ¶ < / a > < / h4 >
< p > By default, watchtower will look for the < code > config.json< / code > file in < code > /< / code > , but this can be changed by setting the < code > DOCKER_CONFIG< / code > environment variable to the directory path where your config is located. This is useful for setups where the config.json file is changed while the watchtower instance is running, as the changes will not be picked up for a mounted file if the inode changes.
Example usage:< / p >
< div class = "highlight" > < pre > < span > < / span > < code > < span class = "nt" > version< / span > < span class = "p" > :< / span > < span class = "w" > < / span > < span class = "s" > " 3.4" < / span >
< span class = "nt" > services< / span > < span class = "p" > :< / span > < span class = "w" > < / span >
< span class = "w" > < / span > < span class = "nt" > watchtower< / span > < span class = "p" > :< / span >
< span class = "w" > < / span > < span class = "nt" > image< / span > < span class = "p" > :< / span > < span class = "w" > < / span > < span class = "l l-Scalar l-Scalar-Plain" > containrrr/watchtower< / span >
< span class = "w" > < / span > < span class = "nt" > environment< / span > < span class = "p" > :< / span >
< span class = "w" > < / span > < span class = "nt" > DOCKER_CONFIG< / span > < span class = "p" > :< / span > < span class = "w" > < / span > < span class = "l l-Scalar l-Scalar-Plain" > /config< / span >
< span class = "w" > < / span > < span class = "nt" > volumes< / span > < span class = "p" > :< / span >
< span class = "w" > < / span > < span class = "p p-Indicator" > -< / span > < span class = "w" > < / span > < span class = "l l-Scalar l-Scalar-Plain" > /etc/watchtower/config/:/config/< / span >
< span class = "w" > < / span > < span class = "p p-Indicator" > -< / span > < span class = "w" > < / span > < span class = "l l-Scalar l-Scalar-Plain" > /var/run/docker.sock:/var/run/docker.sock< / span >
< / code > < / pre > < / div >
< h2 id = "credential_helpers" > Credential helpers< a class = "headerlink" href = "#credential_helpers" title = "Permanent link" > ¶ < / a > < / h2 >
< p > Some private Docker registries (the most prominent probably being AWS ECR) use non-standard ways of authentication.
To be able to use this together with watchtower, we need to use a credential helper.< / p >
< p > To keep the image size small we've decided to not include any helpers in the watchtower image, instead we'll put the
helper in a separate container and mount it using volumes.< / p >
< h3 id = "example" > Example< a class = "headerlink" href = "#example" title = "Permanent link" > ¶ < / a > < / h3 >
< p > Example implementation for use with < a href = "https://github.com/awslabs/amazon-ecr-credential-helper" > amazon-ecr-credential-helper< / a > :< / p >
< p > Use the dockerfile below to build the < a href = "https://github.com/awslabs/amazon-ecr-credential-helper" > amazon-ecr-credential-helper< / a > ,
in a volume that may be mounted onto your watchtower container.< / p >
< ol >
< li >
< p > Create the Dockerfile (contents below):
< div class = "highlight" > < pre > < span > < / span > < code > < span class = "k" > FROM< / span > < span class = "w" > < / span > < span class = "s" > golang:1.17< / span >
< span class = "k" > ENV< / span > < span class = "w" > < / span > GO111MODULE< span class = "w" > < / span > off
< span class = "k" > ENV< / span > < span class = "w" > < / span > CGO_ENABLED< span class = "w" > < / span > < span class = "m" > 0< / span >
< span class = "k" > ENV< / span > < span class = "w" > < / span > REPO< span class = "w" > < / span > github.com/awslabs/amazon-ecr-credential-helper/ecr-login/cli/docker-credential-ecr-login
< span class = "k" > RUN< / span > < span class = "w" > < / span > go< span class = "w" > < / span > get< span class = "w" > < / span > -u< span class = "w" > < / span > < span class = "nv" > $REPO< / span >
< span class = "k" > RUN< / span > < span class = "w" > < / span > rm< span class = "w" > < / span > /go/bin/docker-credential-ecr-login
< span class = "k" > RUN< / span > < span class = "w" > < / span > go< span class = "w" > < / span > build< span class = "w" > < / span > < span class = "se" > \< / span >
< span class = "w" > < / span > -o< span class = "w" > < / span > /go/bin/docker-credential-ecr-login< span class = "w" > < / span > < span class = "se" > \< / span >
< span class = "w" > < / span > /go/src/< span class = "nv" > $REPO< / span >
< span class = "k" > WORKDIR< / span > < span class = "w" > < / span > < span class = "s" > /go/bin/< / span >
< / code > < / pre > < / div > < / p >
< / li >
< li >
< p > Use the following commands to build the aws-ecr-dock-cred-helper and store it's output in a volume:
< div class = "highlight" > < pre > < span > < / span > < code > < span class = "c1" > # Create a volume to store the command (once built)< / span >
docker< span class = "w" > < / span > volume< span class = "w" > < / span > create< span class = "w" > < / span > helper< span class = "w" > < / span >
< span class = "c1" > # Build the container< / span >
docker< span class = "w" > < / span > build< span class = "w" > < / span > -t< span class = "w" > < / span > aws-ecr-dock-cred-helper< span class = "w" > < / span > .
< span class = "c1" > # Build the command and store it in the new volume in the /go/bin directory.< / span >
docker< span class = "w" > < / span > run< span class = "w" > < / span > -d< span class = "w" > < / span > --rm< span class = "w" > < / span > --name< span class = "w" > < / span > aws-cred-helper< span class = "w" > < / span > < span class = "se" > \< / span >
< span class = "w" > < / span > --volume< span class = "w" > < / span > helper:/go/bin< span class = "w" > < / span > aws-ecr-dock-cred-helper
< / code > < / pre > < / div > < / p >
< / li >
< li >
< p > Create a configuration file for docker, and store it in $HOME/.docker/config.json (replace the < AWS_ACCOUNT_ID >
placeholders with your AWS Account ID and < AWS_ECR_REGION > with your AWS ECR Region):
< div class = "highlight" > < pre > < span > < / span > < code > < span class = "p" > {< / span >
< span class = "w" > < / span > < span class = "nt" > " credsStore" < / span > < span class = "w" > < / span > < span class = "p" > :< / span > < span class = "w" > < / span > < span class = "s2" > " ecr-login" < / span > < span class = "p" > ,< / span >
< span class = "w" > < / span > < span class = "nt" > " HttpHeaders" < / span > < span class = "w" > < / span > < span class = "p" > :< / span > < span class = "w" > < / span > < span class = "p" > {< / span >
< span class = "w" > < / span > < span class = "nt" > " User-Agent" < / span > < span class = "w" > < / span > < span class = "p" > :< / span > < span class = "w" > < / span > < span class = "s2" > " Docker-Client/19.03.1 (XXXXXX)" < / span >
< span class = "w" > < / span > < span class = "p" > },< / span >
< span class = "w" > < / span > < span class = "nt" > " auths" < / span > < span class = "w" > < / span > < span class = "p" > :< / span > < span class = "w" > < / span > < span class = "p" > {< / span >
< span class = "w" > < / span > < span class = "nt" > " < AWS_ACCOUNT_ID> .dkr.ecr.< AWS_ECR_REGION> .amazonaws.com" < / span > < span class = "w" > < / span > < span class = "p" > :< / span > < span class = "w" > < / span > < span class = "p" > {}< / span >
< span class = "w" > < / span > < span class = "p" > },< / span >
< span class = "w" > < / span > < span class = "nt" > " credHelpers" < / span > < span class = "p" > :< / span > < span class = "w" > < / span > < span class = "p" > {< / span >
< span class = "w" > < / span > < span class = "nt" > " < AWS_ACCOUNT_ID> .dkr.ecr.< AWS_ECR_REGION> .amazonaws.com" < / span > < span class = "w" > < / span > < span class = "p" > :< / span > < span class = "w" > < / span > < span class = "s2" > " ecr-login" < / span >
< span class = "w" > < / span > < span class = "p" > }< / span >
< span class = "p" > }< / span >
< / code > < / pre > < / div > < / p >
< / li >
< li >
< p > Create a docker-compose file (as an example) to help launch the container:
< div class = "highlight" > < pre > < span > < / span > < code > < span class = "nt" > version< / span > < span class = "p" > :< / span > < span class = "w" > < / span > < span class = "s" > " 3.4" < / span >
< span class = "nt" > services< / span > < span class = "p" > :< / span >
< span class = "w" > < / span > < span class = "c1" > # Check for new images and restart things if a new image exists< / span >
< span class = "w" > < / span > < span class = "c1" > # for any of our containers.< / span >
< span class = "w" > < / span > < span class = "nt" > watchtower< / span > < span class = "p" > :< / span >
< span class = "w" > < / span > < span class = "nt" > image< / span > < span class = "p" > :< / span > < span class = "w" > < / span > < span class = "l l-Scalar l-Scalar-Plain" > containrrr/watchtower:latest< / span >
< span class = "w" > < / span > < span class = "nt" > volumes< / span > < span class = "p" > :< / span >
< span class = "w" > < / span > < span class = "p p-Indicator" > -< / span > < span class = "w" > < / span > < span class = "l l-Scalar l-Scalar-Plain" > /var/run/docker.sock:/var/run/docker.sock< / span >
< span class = "w" > < / span > < span class = "p p-Indicator" > -< / span > < span class = "w" > < / span > < span class = "l l-Scalar l-Scalar-Plain" > .docker/config.json:/config.json< / span >
< span class = "w" > < / span > < span class = "p p-Indicator" > -< / span > < span class = "w" > < / span > < span class = "l l-Scalar l-Scalar-Plain" > helper:/go/bin< / span >
< span class = "w" > < / span > < span class = "nt" > environment< / span > < span class = "p" > :< / span >
< span class = "w" > < / span > < span class = "p p-Indicator" > -< / span > < span class = "w" > < / span > < span class = "l l-Scalar l-Scalar-Plain" > HOME=/< / span >
< span class = "w" > < / span > < span class = "p p-Indicator" > -< / span > < span class = "w" > < / span > < span class = "l l-Scalar l-Scalar-Plain" > PATH=$PATH:/go/bin< / span >
< span class = "w" > < / span > < span class = "p p-Indicator" > -< / span > < span class = "w" > < / span > < span class = "l l-Scalar l-Scalar-Plain" > AWS_REGION=us-west-1< / span >
< span class = "nt" > volumes< / span > < span class = "p" > :< / span >
< span class = "w" > < / span > < span class = "nt" > helper< / span > < span class = "p" > :< / span > < span class = "w" > < / span >
< span class = "w" > < / span > < span class = "nt" > external< / span > < span class = "p" > :< / span > < span class = "w" > < / span > < span class = "l l-Scalar l-Scalar-Plain" > true< / span >
< / code > < / pre > < / div > < / p >
< / li >
< / ol >
< p > A few additional notes:< / p >
< ol >
< li >
< p > With docker-compose the volume (helper, in this case) MUST be set to < code > external: true< / code > , otherwise docker-compose
will preface it with the directory name.< / p >
< / li >
< li >
< p > Note that "credsStore" : "ecr-login" is needed - and in theory if you have that you can remove the
credHelpers section< / p >
< / li >
< li >
< p > I have this running on an EC2 instance that has credentials assigned to it - so no keys are needed; however,
you may need to include the < code > AWS_ACCESS_KEY_ID< / code > and < code > AWS_SECRET_ACCESS_KEY< / code > environment variables as well.< / p >
< / li >
< li >
< p > An alternative to adding the various variables is to create a ~/.aws/config and ~/.aws/credentials files and
place the settings there, then mount the ~/.aws directory to / in the container.< / p >
< / li >
< / ol >
< / article >
< / div >
< / div >
< / main >
< footer class = "md-footer" >
< div class = "md-footer-meta md-typeset" >
< div class = "md-footer-meta__inner md-grid" >
< div class = "md-copyright" >
Made with
< a href = "https://squidfunk.github.io/mkdocs-material/" target = "_blank" rel = "noopener" >
Material for MkDocs
< / a >
< / div >
< / div >
< / div >
< / footer >
< / div >
< div class = "md-dialog" data-md-component = "dialog" >
< div class = "md-dialog__inner md-typeset" > < / div >
< / div >
< script id = "__config" type = "application/json" > { "base" : ".." , "features" : [ ] , "search" : "../assets/javascripts/workers/search.f886a092.min.js" , "translations" : { "clipboard.copied" : "Copied to clipboard" , "clipboard.copy" : "Copy to clipboard" , "search.result.more.one" : "1 more on this page" , "search.result.more.other" : "# more on this page" , "search.result.none" : "No matching documents" , "search.result.one" : "1 matching document" , "search.result.other" : "# matching documents" , "search.result.placeholder" : "Type to start searching" , "search.result.term.missing" : "Missing" , "select.version" : "Select version" } } < / script >
< script src = "../assets/javascripts/bundle.81fa17fe.min.js" > < / script >
< / body >
< / html >