├── .dockerignore ├── .gitignore ├── Dockerfile ├── LICENSE.md ├── README.md ├── go.mod ├── go.sum └── main.go /.dockerignore: -------------------------------------------------------------------------------- 1 | /docker-show-context_* 2 | .git 3 | .gitignore 4 | *.md -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /docker-show-context_* 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.11 AS builder 2 | WORKDIR /app 3 | COPY . . 4 | ENV GO111MODULE=on 5 | RUN go build -o docker-show-context . 6 | 7 | FROM alpine:latest 8 | COPY --from=builder /app/docker-show-context /usr/local/bin 9 | RUN apk add --no-cache libc6-compat 10 | WORKDIR /data 11 | ENTRYPOINT ["docker-show-context"] 12 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Peter Waller
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 | # `docker-show-context` 2 | 3 | Ever wonder why docker pauses when you do `docker build`, and what you can do 4 | about it? You know, when it says `Sending build context to Docker daemon`? 5 | 6 | This program shows where time and bytes are spent when building a docker context. 7 | 8 | It is based directly on the same logic that Docker itself uses to build the 9 | context. 10 | 11 | ## Getting started (docker): 12 | 13 | ```sh 14 | docker build -t docker-show-context https://github.com/pwaller/docker-show-context.git 15 | docker run --rm -v $PWD:/data docker-show-context 16 | ``` 17 | 18 | ## Getting started (binaries): 19 | 20 | Binaries are available on the 21 | [releases page](https://github.com/pwaller/docker-show-context/releases). 22 | Just grab the binary and put it in your path, then invoke it as 23 | `docker-show-context`. Use at your own risk. 24 | 25 | ## Getting started (building from source): 26 | 27 | You will need go 1.11 or more recent, which can be obtained from 28 | [the go website](https://golang.org/dl). 29 | 30 | Then run: 31 | 32 | ``` 33 | git clone https://github.com/pwaller/docker-show-context 34 | cd docker-show-context 35 | GO111MODULE=on go install -v 36 | ``` 37 | 38 | # What the output looks like 39 | 40 | The output looks something like this. It's easy to see now that I accidentally 41 | included some large binary content (`*.deb` and `*.pdf` files in particular), 42 | so I can now go and add those to my `.dockerignore` or delete them. 43 | 44 | ``` 45 | $ cd ~/path/to/project/using/docker 46 | $ docker-show-context 47 | Scanning local directory (in tar / on disk): 48 | 24 / 1057 (62 / 216 MiB) (0.0s elapsed) .. completed 49 | 50 | Excluded by .dockerignore: 1033 files totalling 153.98 MiB 51 | 52 | Final .tar: 53 | 24 files totalling 61.83 MiB (+ 0.02 MiB tar overhead) 54 | Took 0.04 seconds to build 55 | 56 | Top 10 directories by time spent: 57 | 40 ms: . 58 | 1 ms: example 59 | 60 | Top 10 directories by storage: 61 | 61.83 MiB: . 62 | 0.00 MiB: example 63 | 64 | Top 10 directories by file count: 65 | 23: . 66 | 1: example 67 | 68 | Top 10 file extensions by storage: 69 | 57.10 MiB: 70 | 4.71 MiB: .exe 71 | 0.01 MiB: .pprof 72 | 0.01 MiB: .md 73 | 0.01 MiB: .go 74 | 0.00 MiB: .sum 75 | 0.00 MiB: .mod 76 | 0.00 MiB: .sh 77 | 0.00 MiB: .gitignore 78 | 0.00 MiB: .dockerignore 79 | ``` 80 | 81 | # Notes about the current behaviour 82 | 83 | This documents the current behaviour, which may not be ideal, but it is what it 84 | is for now. Pull requests welcome. 85 | 86 | * The amounts shown don't show recursive usage, they just show a single level 87 | of the directory. (Otherwise, the root would always be the biggest thing). 88 | 89 | * Time records the amount of time between `tarFile.Next()` calls. I assume that 90 | this approximates the amount of time `docker/pkg/archive` spent constructing 91 | one tar entry. It might not be precise. 92 | 93 | * "Total content" shows the uncompressed bytes inside files inside the tar. 94 | The total amount sent to the docker daemon is this amount plus the tar 95 | overhead. 96 | 97 | * At this moment, only running with the build context root as the current 98 | working directory is supported, with a dockerfile named `Dockerfile`. 99 | Pull requests welcome to add parameters, so long as the existing default 100 | behaviour is preserved. 101 | 102 | # How can I use this to make building faster? 103 | 104 | Frequently, I find that `docker build` suddenly takes longer than I expect. It 105 | is often the case that I have accidentally included some binaries or something 106 | which I did not intend to include. This the purpose of this tool is to give 107 | visibility into this, taking into account your existing `.dockerignore`, 108 | so that you can improve your `.dockerfile` or delete assets you don't need. 109 | 110 | It scratches an itch. 111 | 112 | # License 113 | 114 | > The MIT License (MIT) 115 | > 116 | > Copyright (c) 2016-2018 Peter Waller
117 | > 118 | > Permission is hereby granted, free of charge, to any person obtaining a copy 119 | > of this software and associated documentation files (the "Software"), to deal 120 | > in the Software without restriction, including without limitation the rights 121 | > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 122 | > copies of the Software, and to permit persons to whom the Software is 123 | > furnished to do so, subject to the following conditions: 124 | > 125 | > The above copyright notice and this permission notice shall be included in all 126 | > copies or substantial portions of the Software. 127 | > 128 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 129 | > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 130 | > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 131 | > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 132 | > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 133 | > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 134 | > SOFTWARE. 135 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/pwaller/docker-show-context 2 | 3 | require ( 4 | github.com/Microsoft/go-winio v0.4.14 // indirect 5 | github.com/Microsoft/hcsshim v0.8.6 // indirect 6 | github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6 // indirect 7 | github.com/docker/docker v1.4.2-0.20191108004417-1a88e0255496 8 | github.com/docker/go-units v0.4.0 // indirect 9 | github.com/golang/protobuf v1.3.2 // indirect 10 | github.com/google/go-cmp v0.3.1 // indirect 11 | github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect 12 | github.com/opencontainers/go-digest v1.0.0-rc1 // indirect 13 | github.com/opencontainers/image-spec v1.0.1 // indirect 14 | github.com/opencontainers/runc v0.1.1 // indirect 15 | github.com/sirupsen/logrus v1.4.2 // indirect 16 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect 17 | golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd // indirect 18 | gotest.tools v2.2.0+incompatible // indirect 19 | ) 20 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU= 2 | github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= 3 | github.com/Microsoft/hcsshim v0.8.6 h1:ZfF0+zZeYdzMIVMZHKtDKJvLHj76XCuVae/jNkjj0IA= 4 | github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= 5 | github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6 h1:NmTXa/uVnDyp0TY5MKi197+3HWcnYWfnHGyaFthlnGw= 6 | github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= 7 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 8 | github.com/docker/docker v0.0.0-20191017212428-1e000435e60d h1:0QAxgI4pvRtTcgcvIo5xSSJPTn0kgEg2PqdcvP2hBJ8= 9 | github.com/docker/docker v0.0.0-20191017212428-1e000435e60d/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= 10 | github.com/docker/docker v1.4.2-0.20191108004417-1a88e0255496 h1:X3W/mc2aCB8NcDE7HsMSw+/VTW3hzAO8PAP7nTyB3ec= 11 | github.com/docker/docker v1.4.2-0.20191108004417-1a88e0255496/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= 12 | github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= 13 | github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= 14 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 15 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 16 | github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= 17 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 18 | github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= 19 | github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 20 | github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= 21 | github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= 22 | github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= 23 | github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= 24 | github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= 25 | github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= 26 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= 27 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 28 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 29 | github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= 30 | github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= 31 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 32 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 33 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 34 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= 35 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 36 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 37 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 38 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 39 | golang.org/x/sys v0.0.0-20191018095205-727590c5006e h1:ZtoklVMHQy6BFRHkbG6JzK+S6rX82//Yeok1vMlizfQ= 40 | golang.org/x/sys v0.0.0-20191018095205-727590c5006e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 41 | golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd h1:3x5uuvBgE6oaXJjCOvpCC1IpgJogqQ+PqGGU3ZxAgII= 42 | golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 43 | gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= 44 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | // Licensed under the MIT License (MIT) 2 | // Copyright (c) 2016 Peter Waller
3 |
4 | package main
5 |
6 | import (
7 | "archive/tar"
8 | "fmt"
9 | "io"
10 | "log"
11 | "os"
12 | "path/filepath"
13 | "sort"
14 | "strings"
15 | "time"
16 |
17 | "github.com/docker/docker/builder/dockerignore"
18 | "github.com/docker/docker/pkg/archive"
19 | "github.com/docker/docker/pkg/fileutils"
20 | )
21 |
22 | // getArchive returns the tarfile io.ReadCloser. It is a direct copy of the
23 | // logic found in the official docker client.
24 | // See