├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── files ├── ecr.ini ├── health-check.sh ├── nginx.conf ├── renew_token.sh ├── root ├── ssl.conf └── startup.sh ├── hosts ├── playbook-docker-registry-proxy.yaml ├── roles └── docker-registry-proxy │ ├── defaults │ └── main.yml │ ├── files │ ├── certificate.pem │ └── key.pem │ └── tasks │ └── main.yaml └── syntax-check.sh /.gitignore: -------------------------------------------------------------------------------- 1 | /dev 2 | /*.retry 3 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openresty/openresty:1.19.9.1-12-alpine 2 | 3 | USER root 4 | 5 | RUN apk add -v --no-cache bind-tools python3 py-pip py3-urllib3 py3-colorama supervisor \ 6 | && mkdir /cache \ 7 | && addgroup -g 110 nginx \ 8 | && adduser -u 110 -D -S -h /cache -s /sbin/nologin -G nginx nginx \ 9 | && pip install --upgrade pip awscli==1.11.183 \ 10 | && apk -v --purge del py-pip 11 | 12 | COPY files/startup.sh files/renew_token.sh files/health-check.sh / 13 | COPY files/ecr.ini /etc/supervisor.d/ecr.ini 14 | COPY files/root /etc/crontabs/root 15 | 16 | COPY files/nginx.conf /usr/local/openresty/nginx/conf/nginx.conf 17 | COPY files/ssl.conf /usr/local/openresty/nginx/conf/ssl.conf 18 | 19 | ENV PORT 5000 20 | RUN chmod a+x /startup.sh /renew_token.sh 21 | 22 | HEALTHCHECK --interval=5s --timeout=5s --retries=3 CMD /health-check.sh 23 | 24 | ENTRYPOINT ["/startup.sh"] 25 | CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"] 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 eSailors IT Solutions GmbH 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
8 | 9 | # aws-ecr-http-proxy 10 | 11 | A very simple nginx push/pull proxy that forwards requests to AWS ECR and caches the responses locally. 12 | 13 | ### Configuration: 14 | The proxy is packaged in a docker container and can be configured with following environment variables: 15 | 16 | | Environment Variable | Description | Status | Default | 17 | | :---------------------------------: | :--------------------------------------------: | :-------------------------------: | :--------: | 18 | | `AWS_REGION` | AWS Region for AWS ECR | Required | | 19 | | `AWS_ACCESS_KEY_ID` | AWS Account Access Key ID | Optional | | 20 | | `AWS_SECRET_ACCESS_KEY` | AWS Account Secret Access Key | Optional | | 21 | | `AWS_USE_EC2_ROLE_FOR_AUTH` | Set this to true if we do want to use aws roles for authentication instead of providing the secret and access keys explicitly | Optional | | 22 | | `UPSTREAM` | URL for AWS ECR | Required | | 23 | | `RESOLVER` | DNS server to be used by proxy | Required | | 24 | | `PORT` | Port on which proxy listens | Required | | 25 | | `CACHE_MAX_SIZE` | Maximum size for cache volume | Optional | `75g` | 26 | | `CACHE_KEY` | Cache key used for the content by nginx | Optional | `$uri` | 27 | | `ENABLE_SSL` | Used to enable SSL/TLS for proxy | Optional | `false` | 28 | | `REGISTRY_HTTP_TLS_KEY` | Path to TLS key in the container | Required with TLS | | 29 | | `REGISTRY_HTTP_TLS_CERTIFICATE` | Path to TLS cert in the container | Required with TLS | | 30 | 31 | ### Example: 32 | 33 | ```sh 34 | docker run -d --name docker-registry-proxy --net=host \ 35 | -v /registry/local-storage/cache:/cache \ 36 | -v /registry/certificate.pem:/opt/ssl/certificate.pem \ 37 | -v /registry/key.pem:/opt/ssl/key.pem \ 38 | -e PORT=5000 \ 39 | -e RESOLVER=8.8.8.8 \ 40 | -e UPSTREAM=https://XXXXXXXXXX.dkr.ecr.eu-central-1.amazonaws.com \ 41 | -e AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} \ 42 | -e AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} \ 43 | -e AWS_REGION=${AWS_DEFAULT_REGION} \ 44 | -e CACHE_MAX_SIZE=100g \ 45 | -e ENABLE_SSL=true \ 46 | -e REGISTRY_HTTP_TLS_KEY=/opt/ssl/key.pem \ 47 | -e REGISTRY_HTTP_TLS_CERTIFICATE=/opt/ssl/certificate.pem \ 48 | esailors/aws-ecr-http-proxy:latest 49 | ``` 50 | 51 | If you ran this command on "registry-proxy.example.com" you can now get your images using `docker pull registry-proxy.example.com:5000/repo/image`. 52 | 53 | ### Deploying the proxy 54 | 55 | #### Deploying with ansible 56 | 57 | Modify the ansible role [variables](https://github.com/eSailors/aws-ecr-http-proxy/tree/master/roles/docker-registry-proxy/defaults) according to your need and run the playbook as follow: 58 | ```sh 59 | ansible-playbook -i hosts playbook-docker-registry-proxy.yaml 60 | ``` 61 | In case you want to enable SSL/TLS please replace the SSL certificates with the valid ones in [roles/docker-registry-proxy/files/*.pem](https://github.com/eSailors/aws-ecr-http-proxy/tree/master/roles/docker-registry-proxy/files) 62 | 63 | #### Deploying on Kubernetes with Helm 64 | You can install on Kubernetes using the [community-maintained chart](https://github.com/evryfs/helm-charts/tree/master/charts/ecr-proxy) like this: 65 | 66 | ```shell 67 | helm repo add evryfs-oss https://evryfs.github.io/helm-charts/ 68 | helm install evryfs-oss/ecr-proxy --name ecr-proxy --namespace ecr-proxy 69 | ``` 70 | 71 | See the [values-file](https://github.com/evryfs/helm-charts/blob/master/charts/ecr-proxy/values.yaml) for configuration parameters. 72 | 73 | 74 | ### Note on SSL/TLS 75 | The proxy is using `HTTP` (plain text) as default protocol for now. So in order to avoid docker client complaining either: 76 | - (**Recommended**) Enable SSL/TLS using `ENABLE_SSL` configuration. For that you will have to mount your **valid** certificate/key in the container and pass the paths using `REGISTRY_HTTP_TLS_*` variables. 77 | - Mark the registry host as insecure in your client [deamon config](https://docs.docker.com/registry/insecure/). 78 | -------------------------------------------------------------------------------- /files/ecr.ini: -------------------------------------------------------------------------------- 1 | [supervisord] 2 | nodaemon=true 3 | 4 | [program:nginx] 5 | command = nginx -g "daemon off;" 6 | user = root 7 | stderr_logfile_maxbytes=0 8 | stdout_logfile_maxbytes=0 9 | stderr_logfile=/dev/stderr 10 | stdout_logfile=/dev/stdout 11 | autostart = true 12 | 13 | [program:crond] 14 | command = crond -f 15 | user = root 16 | autostart = true 17 | -------------------------------------------------------------------------------- /files/health-check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | wget localhost:PORT/healthz -q -O - > /dev/null 2>&1 3 | -------------------------------------------------------------------------------- /files/nginx.conf: -------------------------------------------------------------------------------- 1 | user nginx; 2 | worker_processes 1; 3 | 4 | events { 5 | worker_connections 1024; 6 | } 7 | 8 | http { 9 | include mime.types; 10 | default_type application/octet-stream; 11 | 12 | keepalive_timeout 65; 13 | sendfile on; 14 | 15 | proxy_cache_path /cache/cache levels=1:2 keys_zone=cache:16m inactive=1y max_size=CACHE_MAX_SIZE use_temp_path=off; 16 | resolver RESOLVER valid=30s; 17 | 18 | # this is necessary for us to be able to disable request buffering in all cases 19 | proxy_http_version 1.1; 20 | 21 | lua_shared_dict token_dict 1m; 22 | 23 | # will run before forking out nginx worker processes 24 | init_by_lua_block { 25 | require "cjson" 26 | 27 | local token_file = io.open('/usr/local/openresty/nginx/token.txt', 'r') 28 | if token_file then 29 | local data = token_file:read() 30 | ngx.shared.token_dict:set("ecr_token", data) 31 | token_file:close() 32 | else 33 | ngx.log(ngx.ERR, "Failed to open token file: /usr/local/openresty/nginx/token.txt") 34 | end 35 | } 36 | 37 | #https://docs.docker.com/registry/recipes/nginx/#setting-things-up 38 | map $upstream_http_docker_distribution_api_version $docker_distribution_api_version { 39 | '' 'registry/2.0'; 40 | } 41 | 42 | server { 43 | listen PORT SSL_LISTEN default_server; 44 | 45 | set_by_lua_block $http_authorization { 46 | return ngx.shared.token_dict:get("ecr_token") 47 | } 48 | 49 | SSL_INCLUDE 50 | 51 | # Cache 52 | add_header X-Cache-Status $upstream_cache_status; 53 | proxy_temp_path /cache/temp 1 2; 54 | proxy_ignore_headers Cache-Control; 55 | 56 | # disable any limits to avoid HTTP 413 for large image uploads 57 | client_max_body_size 0; 58 | 59 | # required to avoid HTTP 411: see Issue #1486 (https://github.com/moby/moby/issues/1486) 60 | chunked_transfer_encoding on; 61 | 62 | # increases timeouts to avoid HTTP 504 63 | proxy_connect_timeout 3s; 64 | proxy_read_timeout 300s; 65 | proxy_send_timeout 300s; 66 | send_timeout 300s; 67 | 68 | # disable proxy request buffering 69 | proxy_request_buffering off; 70 | 71 | add_header 'Docker-Distribution-Api-Version' $docker_distribution_api_version always; 72 | add_header "Access-Control-Allow-Origin" "*"; 73 | 74 | # health check 75 | location /healthz { 76 | return 200; 77 | } 78 | 79 | location / { 80 | set $url UPSTREAM; 81 | proxy_pass $url; 82 | proxy_redirect $url SCHEME://$host:PORT; 83 | 84 | # Add AWS ECR authentication headers 85 | proxy_set_header X-Real-IP $remote_addr; 86 | proxy_set_header X-Forwarded-For $remote_addr; 87 | proxy_set_header X-Forwarded-User "Basic $http_authorization"; 88 | proxy_set_header Authorization "Basic $http_authorization"; 89 | proxy_set_header X-Forwarded-Proto $scheme; 90 | 91 | } 92 | 93 | # Content addressable files like blobs. 94 | # https://docs.docker.com/registry/spec/api/#blob 95 | location ~ ^/v2/.*/blobs/[a-z0-9]+:[a-f0-9]+$ { 96 | set $url UPSTREAM; 97 | proxy_pass $url; 98 | proxy_redirect $url SCHEME://$host:PORT; 99 | 100 | # Add AWS ECR authentication headers 101 | proxy_set_header X-Real-IP $remote_addr; 102 | proxy_set_header X-Forwarded-For $remote_addr; 103 | proxy_set_header X-Forwarded-User "Basic $http_authorization"; 104 | proxy_set_header Authorization "Basic $http_authorization"; 105 | proxy_set_header X-Forwarded-Proto $scheme; 106 | 107 | # When accessing image blobs using HTTP GET AWS ECR redirects with 108 | # s3 buckets uri to download the image. This needs to handled by 109 | # nginx rather then docker client for caching. 110 | proxy_intercept_errors on; 111 | error_page 301 302 307 = @handle_redirect; 112 | } 113 | 114 | # No authentication headers needed as ECR returns s3 uri with details in 115 | # query params. Also the params should be part of cache key for nginx to 116 | # issue HIT for same image blob. 117 | location @handle_redirect { 118 | set $saved_redirect_location '$upstream_http_location'; 119 | proxy_pass $saved_redirect_location; 120 | proxy_cache cache; 121 | proxy_cache_key CACHE_KEY; 122 | proxy_cache_valid 200 1y; 123 | proxy_cache_use_stale error timeout invalid_header updating 124 | http_500 http_502 http_503 http_504; 125 | proxy_cache_lock on; 126 | } 127 | 128 | location ~ ^/v2/.*/.*/tags/list+$ { 129 | # get paginated list of tags 130 | content_by_lua_block { 131 | local location, tags, cjson = ngx.var.uri, {}, require "cjson" 132 | while true do 133 | local res = ngx.location.capture("/get_tags", 134 | { args = { req_uri = location } } 135 | ) 136 | if res.status == ngx.HTTP_NOT_FOUND and table.getn(tags) == 0 then 137 | ngx.status = ngx.HTTP_NOT_FOUND 138 | ngx.print(res.body) 139 | ngx.exit(0) 140 | end 141 | local data = cjson.decode(res.body) 142 | for _,v in ipairs(data['tags']) do 143 | table.insert(tags, v) 144 | end 145 | if res.header["Link"] ~= nil then 146 | location = res.header["Link"]:match("/v2[^>]+") 147 | else 148 | ngx.print(cjson.encode{name = data['name'], tags = tags }) 149 | ngx.exit(ngx.HTTP_OK) 150 | end 151 | end 152 | } 153 | } 154 | 155 | # Helper location for getting tags from upstream repository 156 | # used for getting paginated tags. 157 | location /get_tags { 158 | internal; 159 | set_unescape_uri $req_uri $arg_req_uri; 160 | proxy_pass UPSTREAM$req_uri; 161 | 162 | # Add AWS ECR authentication headers 163 | proxy_set_header X-Real-IP $remote_addr; 164 | proxy_set_header X-Forwarded-For $remote_addr; 165 | proxy_set_header X-Forwarded-User "Basic $http_authorization"; 166 | proxy_set_header Authorization "Basic $http_authorization"; 167 | proxy_set_header X-Forwarded-Proto $scheme; 168 | 169 | } 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /files/renew_token.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -xe 4 | 5 | # update the auth token 6 | CONFIG=/usr/local/openresty/nginx/conf/nginx.conf 7 | AUTH=$(grep X-Forwarded-User $CONFIG | awk '{print $4}'| uniq|tr -d "\n\r") 8 | 9 | 10 | # retry till new get new token 11 | while true; do 12 | TOKEN=$(aws ecr get-authorization-token --query 'authorizationData[*].authorizationToken' --output text) 13 | [ ! -z "${TOKEN}" ] && break 14 | echo "Warn: Unable to get new token, wait and retry!" 15 | sleep 30 16 | done 17 | 18 | set +x 19 | echo $TOKEN > /usr/local/openresty/nginx/token.txt 20 | set -x 21 | 22 | nginx -s reload 23 | -------------------------------------------------------------------------------- /files/root: -------------------------------------------------------------------------------- 1 | # Refresh the AWS ECR token periodically. 2 | # min hour day month weekday command 3 | 0 */6 * * * /renew_token.sh 4 | -------------------------------------------------------------------------------- /files/ssl.conf: -------------------------------------------------------------------------------- 1 | ssl_certificate_key REGISTRY_HTTP_TLS_KEY; 2 | ssl_certificate REGISTRY_HTTP_TLS_CERTIFICATE; 3 | 4 | ssl_protocols TLSv1.2; 5 | ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; 6 | ssl_prefer_server_ciphers on; 7 | 8 | add_header Strict-Transport-Security max-age=31536000; 9 | -------------------------------------------------------------------------------- /files/startup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | set -x 5 | 6 | if [ -z "$UPSTREAM" ] ; then 7 | echo "UPSTREAM not set." 8 | exit 1 9 | fi 10 | 11 | if [ -z "$PORT" ] ; then 12 | echo "PORT not set." 13 | exit 1 14 | fi 15 | 16 | if [ -z "$RESOLVER" ] ; then 17 | echo "RESOLVER not set." 18 | exit 1 19 | fi 20 | 21 | if [ -z "$AWS_REGION" ] ; then 22 | echo "AWS_REGION not set." 23 | exit 1 24 | fi 25 | 26 | if [ -z "$AWS_USE_EC2_ROLE_FOR_AUTH" ] || [ "$AWS_USE_EC2_ROLE_FOR_AUTH" != "true" ]; then 27 | if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then 28 | echo "AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY not set." 29 | exit 1 30 | fi 31 | fi 32 | 33 | UPSTREAM_WITHOUT_PORT=$( echo ${UPSTREAM} | sed -r "s/.*:\/\/(.*):.*/\1/g") 34 | echo Using resolver $RESOLVER and $UPSTREAM [$(dig +short ${UPSTREAM_WITHOUT_PORT})] as upstream. 35 | 36 | CACHE_MAX_SIZE=${CACHE_MAX_SIZE:-75g} 37 | echo Using cache max size $CACHE_MAX_SIZE 38 | 39 | CACHE_KEY=${CACHE_KEY:='$uri'} 40 | echo Using cache key $CACHE_KEY 41 | 42 | SCHEME=http 43 | CONFIG=/usr/local/openresty/nginx/conf/nginx.conf 44 | SSL_CONFIG=/usr/local/openresty/nginx/conf/ssl.conf 45 | 46 | if [ "$ENABLE_SSL" ]; then 47 | sed -i -e s!REGISTRY_HTTP_TLS_CERTIFICATE!"$REGISTRY_HTTP_TLS_CERTIFICATE"!g $SSL_CONFIG 48 | sed -i -e s!REGISTRY_HTTP_TLS_KEY!"$REGISTRY_HTTP_TLS_KEY"!g $SSL_CONFIG 49 | SSL_LISTEN="ssl" 50 | SSL_INCLUDE="include $SSL_CONFIG;" 51 | SCHEME="https" 52 | fi 53 | 54 | # Update nginx config 55 | sed -i -e s!UPSTREAM!"$UPSTREAM"!g $CONFIG 56 | sed -i -e s!PORT!"$PORT"!g $CONFIG 57 | sed -i -e s!RESOLVER!"$RESOLVER"!g $CONFIG 58 | sed -i -e s!CACHE_MAX_SIZE!"$CACHE_MAX_SIZE"!g $CONFIG 59 | sed -i -e s!CACHE_KEY!"$CACHE_KEY"!g $CONFIG 60 | sed -i -e s!SCHEME!"$SCHEME"!g $CONFIG 61 | sed -i -e s!SSL_INCLUDE!"$SSL_INCLUDE"!g $CONFIG 62 | sed -i -e s!SSL_LISTEN!"$SSL_LISTEN"!g $CONFIG 63 | 64 | # Update health-check 65 | sed -i -e s!PORT!"$PORT"!g /health-check.sh 66 | 67 | # setup ~/.aws directory 68 | AWS_FOLDER='/root/.aws' 69 | mkdir -p ${AWS_FOLDER} 70 | echo "[default]" > ${AWS_FOLDER}/config 71 | echo "region = $AWS_REGION" >> ${AWS_FOLDER}/config 72 | 73 | if [ -z "$AWS_USE_EC2_ROLE_FOR_AUTH" ] || [ "$AWS_USE_EC2_ROLE_FOR_AUTH" != "true" ]; then 74 | echo "[default]" > ${AWS_FOLDER}/credentials 75 | echo "aws_access_key_id=$AWS_ACCESS_KEY_ID" >> ${AWS_FOLDER}/credentials 76 | echo "aws_secret_access_key=$AWS_SECRET_ACCESS_KEY" >> ${AWS_FOLDER}/credentials 77 | fi 78 | chmod 600 -R ${AWS_FOLDER} 79 | 80 | set +x 81 | # add the auth token in default.conf 82 | AUTH=$(grep X-Forwarded-User $CONFIG | awk '{print $4}'| uniq|tr -d "\n\r") 83 | TOKEN=$(aws ecr get-authorization-token --query 'authorizationData[*].authorizationToken' --output text) 84 | 85 | echo $TOKEN > /usr/local/openresty/nginx/token.txt 86 | 87 | set -x 88 | # make sure cache directory has correct ownership 89 | chown -R nginx:nginx /cache 90 | 91 | exec "$@" 92 | -------------------------------------------------------------------------------- /hosts: -------------------------------------------------------------------------------- 1 | [docker-registry-proxy] 2 | localhost ansible_connection=local 3 | -------------------------------------------------------------------------------- /playbook-docker-registry-proxy.yaml: -------------------------------------------------------------------------------- 1 | - hosts: docker-registry-proxy 2 | roles: 3 | - role: docker-registry-proxy 4 | -------------------------------------------------------------------------------- /roles/docker-registry-proxy/defaults/main.yml: -------------------------------------------------------------------------------- 1 | docker_proxy_clear_cache: false 2 | docker_proxy_cache_limit: 75g 3 | docker_proxy_cache_path: /registry/local-storage/cache 4 | docker_proxy_version: latest 5 | docker_proxy_backend: "XXXXXXXX.dkr.ecr.eu-central-1.amazonaws.com" 6 | docker_proxy_backend_schema: https 7 | docker_proxy_backend_resolver: "8.8.8.8" 8 | docker_proxy_ecr_access_id: 9 | docker_proxy_ecr_secret_key: 10 | docker_proxy_ecr_region: 11 | 12 | # ssl config 13 | docker_proxy_ssl_enabled: false 14 | docker_proxy_ssl_copy_certs: false 15 | docker_proxy_ssl_host_path: /registry 16 | docker_proxy_ssl_host_cert_name: certificate.pem 17 | docker_proxy_ssl_host_key_name: key.pem 18 | docker_proxy_ssl_container_path: /opt/nginx 19 | -------------------------------------------------------------------------------- /roles/docker-registry-proxy/files/certificate.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | 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 31 | XipqaCA= 32 | -----END CERTIFICATE----- 33 | -------------------------------------------------------------------------------- /roles/docker-registry-proxy/files/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | 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 51 | UFg2hiaXvnBuMgGHodqIzeQarqKv 52 | -----END PRIVATE KEY----- 53 | -------------------------------------------------------------------------------- /roles/docker-registry-proxy/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | - name: Create cache directory 2 | become: true 3 | file: path={{ docker_proxy_cache_path }} state=directory mode=0755 recurse=true 4 | 5 | - name: Copy the ssl certificates 6 | become: true 7 | copy: 8 | src: "{{ item }}" 9 | dest: "{{ docker_proxy_ssl_host_path }}/{{ item }}" 10 | with_items: 11 | - certificate.pem 12 | - key.pem 13 | when: 14 | - docker_proxy_ssl_enabled | bool 15 | - docker_proxy_ssl_copy_certs | bool 16 | 17 | - name: Print current cache directory size information 18 | become: true 19 | command: du -hs {{ docker_proxy_cache_path }} 20 | 21 | - name: Pull proxy container 22 | become: true 23 | command: > 24 | docker pull esailors/aws-ecr-http-proxy:{{ docker_proxy_version }} 25 | tags: 26 | - pull-image 27 | 28 | - name: Remove previous proxy container 29 | become: true 30 | command: docker rm -fv docker-registry-proxy 31 | ignore_errors: true 32 | 33 | - name: Clear local cache 34 | become: true 35 | command: rm -rf {{ docker_proxy_cache_path }} 36 | when: docker_proxy_clear_cache|bool 37 | 38 | - name: Run new docker registry proxy container 39 | become: true 40 | command: > 41 | docker run -d 42 | --name docker-registry-proxy 43 | --net host 44 | --restart=unless-stopped 45 | 46 | -v {{ docker_proxy_cache_path }}:/cache 47 | 48 | {% if docker_proxy_ssl_enabled | bool %} 49 | -v {{ docker_proxy_ssl_host_path }}/{{ docker_proxy_ssl_host_cert_name }}:{{ docker_proxy_ssl_container_path }}/certificate.pem 50 | -v {{ docker_proxy_ssl_host_path }}/{{ docker_proxy_ssl_host_key_name }}:{{ docker_proxy_ssl_container_path }}/key.pem 51 | 52 | -e ENABLE_SSL=true 53 | -e REGISTRY_HTTP_TLS_KEY={{ docker_proxy_ssl_container_path }}/key.pem 54 | -e REGISTRY_HTTP_TLS_CERTIFICATE={{ docker_proxy_ssl_container_path }}/certificate.pem 55 | {% endif %} 56 | 57 | -e RESOLVER={{ docker_proxy_backend_resolver }} 58 | -e PORT=5000 59 | -e UPSTREAM={{ docker_proxy_backend_schema }}://{{ docker_proxy_backend }} 60 | -e CACHE_MAX_SIZE={{ docker_proxy_cache_limit }} 61 | -e AWS_ACCESS_KEY_ID={{ docker_proxy_ecr_access_id }} 62 | -e AWS_SECRET_ACCESS_KEY={{ docker_proxy_ecr_secret_key }} 63 | -e AWS_REGION={{ docker_proxy_ecr_region }} 64 | 65 | esailors/aws-ecr-http-proxy:{{ docker_proxy_version }} 66 | -------------------------------------------------------------------------------- /syntax-check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | echo "Performing syntax check on ansible playbooks" 6 | 7 | ansible-playbook -i hosts --syntax-check playbook-docker-registry-proxy.yaml 8 | --------------------------------------------------------------------------------