Build docker-proxy from git checkout like other external binaries

This means we can vendor libnetwork without special casing, and
it is built the same way as the other external binaries.

Signed-off-by: Justin Cormack <justin.cormack@docker.com>
This commit is contained in:
Justin Cormack 2016-10-19 00:30:47 +01:00
parent ce6cfef36d
commit 3996975b08
20 changed files with 35 additions and 428 deletions

View file

@ -222,10 +222,10 @@ RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
hello-world:latest@sha256:8be990ef2aeb16dbcb9271ddfe2610fa6658d13f6dfb8bc72074cc1ca36966a7
# See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
# Install tomlv, runc, containerd and grimes
# Install tomlv, runc, containerd, grimes, docker-proxy
# Please edit hack/dockerfile/install-binaries.sh to update them.
COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
RUN /tmp/install-binaries.sh tomlv runc containerd grimes
RUN /tmp/install-binaries.sh tomlv runc containerd grimes proxy
# Wrap all commands in the "docker-in-docker" script to allow nested containers
ENTRYPOINT ["hack/dind"]

View file

@ -165,10 +165,10 @@ RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
aarch64/hello-world:latest@sha256:65a4a158587b307bb02db4de41b836addb0c35175bdc801367b1ac1ddeb9afda
# See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
# Install tomlv, runc, containerd and grimes
# Install tomlv, runc, containerd, grimes, docker-proxy
# Please edit hack/dockerfile/install-binaries.sh to update them.
COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
RUN /tmp/install-binaries.sh tomlv runc containerd grimes
RUN /tmp/install-binaries.sh tomlv runc containerd grimes proxy
# Wrap all commands in the "docker-in-docker" script to allow nested containers
ENTRYPOINT ["hack/dind"]

View file

@ -164,10 +164,10 @@ RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
armhf/hello-world:latest@sha256:161dcecea0225975b2ad5f768058212c1e0d39e8211098666ffa1ac74cfb7791
# See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
# Install tomlv, runc, containerd and grimes
# Install tomlv, runc, containerd, grimes, docker-proxy
# Please edit hack/dockerfile/install-binaries.sh to update them.
COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
RUN /tmp/install-binaries.sh tomlv runc containerd grimes
RUN /tmp/install-binaries.sh tomlv runc containerd grimes proxy
ENTRYPOINT ["hack/dind"]

View file

@ -183,10 +183,10 @@ RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
ppc64le/hello-world:latest@sha256:186a40a9a02ca26df0b6c8acdfb8ac2f3ae6678996a838f977e57fac9d963974
# See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
# Install tomlv, runc, containerd and grimes
# Install tomlv, runc, containerd, grimes, docker-proxy
# Please edit hack/dockerfile/install-binaries.sh to update them.
COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
RUN /tmp/install-binaries.sh tomlv runc containerd grimes
RUN /tmp/install-binaries.sh tomlv runc containerd grimes proxy
# Wrap all commands in the "docker-in-docker" script to allow nested containers
ENTRYPOINT ["hack/dind"]

View file

@ -175,10 +175,10 @@ RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
s390x/hello-world:latest@sha256:780d80b3a7677c3788c0d5cd9168281320c8d4a6d9183892d8ee5cdd610f5699
# See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
# Install tomlv, runc, containerd and grimes
# Install tomlv, runc, containerd, grimes, docker-proxy
# Please edit hack/dockerfile/install-binaries.sh to update them.
COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
RUN /tmp/install-binaries.sh tomlv runc containerd grimes
RUN /tmp/install-binaries.sh tomlv runc containerd grimes proxy
# Wrap all commands in the "docker-in-docker" script to allow nested containers
ENTRYPOINT ["hack/dind"]

View file

@ -56,10 +56,10 @@ ENV PATH /go/bin:/usr/local/go/bin:$PATH
ENV GOPATH /go:/go/src/github.com/docker/docker/vendor
ENV CGO_LDFLAGS -L/lib
# Install runc, containerd and grimes
# Install runc, containerd, grimes and docker-proxy
# Please edit hack/dockerfile/install-binaries.sh to update them.
COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
RUN /tmp/install-binaries.sh runc containerd grimes
RUN /tmp/install-binaries.sh runc containerd grimes proxy
ENV AUTO_GOPATH 1
WORKDIR /usr/src/docker

View file

@ -124,9 +124,6 @@ clean() {
findArgs+=( -path "vendor/src/$import" )
done
# The docker proxy command is built from libnetwork
findArgs+=( -or -path vendor/src/github.com/docker/libnetwork/cmd/proxy )
local IFS=$'\n'
local prune=( $($find vendor -depth -type d -not '(' "${findArgs[@]}" ')') )
unset IFS

View file

@ -6,6 +6,7 @@ TOMLV_COMMIT=9baf8a8a9f2ed20a8e54160840c492f937eeaf9a
RUNC_COMMIT=02f8fa7863dd3f82909a73e2061897828460d52f
CONTAINERD_COMMIT=52ef1ceb4b660c42cf4ea9013180a5663968d4c7
GRIMES_COMMIT=74341e923bdf06cfb6b70cf54089c4d3ac87ec2d
LIBNETWORK_COMMIT=0f534354b813003a754606689722fe253101bc4e
export GOPATH="$(mktemp -d)"
@ -66,8 +67,16 @@ do
cp init /usr/local/bin/docker-init
;;
proxy)
echo "Install docker-proxy version $LIBNETWORK_COMMIT"
git clone https://github.com/docker/libnetwork.git "$GOPATH/src/github.com/docker/libnetwork"
cd "$GOPATH/src/github.com/docker/libnetwork"
git checkout -q "$LIBNETWORK_COMMIT"
CGO_ENABLED=0 go build -v -o /usr/local/bin/docker-proxy github.com/docker/libnetwork/cmd/proxy
;;
*)
echo echo "Usage: $0 [tomlv|runc|containerd|grimes]"
echo echo "Usage: $0 [tomlv|runc|containerd|grimes|proxy]"
exit 1
esac

View file

@ -263,7 +263,7 @@ copy_binaries() {
if [ "$(go env GOOS)/$(go env GOARCH)" == "$(go env GOHOSTOS)/$(go env GOHOSTARCH)" ]; then
if [ -x /usr/local/bin/docker-runc ]; then
echo "Copying nested executables into $dir"
for file in containerd containerd-shim containerd-ctr runc init; do
for file in containerd containerd-shim containerd-ctr runc init proxy; do
cp `which "docker-$file"` "$dir/"
if [ "$2" == "hash" ]; then
hash_files "$dir/docker-$file"

View file

@ -24,11 +24,12 @@ override_dh_auto_install:
mkdir -p debian/docker-engine/usr/bin
cp -aT "$$(readlink -f bundles/$(VERSION)/dynbinary-client/docker)" debian/docker-engine/usr/bin/docker
cp -aT "$$(readlink -f bundles/$(VERSION)/dynbinary-daemon/dockerd)" debian/docker-engine/usr/bin/dockerd
cp -aT "$$(readlink -f bundles/$(VERSION)/dynbinary-daemon/docker-proxy)" debian/docker-engine/usr/bin/docker-proxy
cp -aT /usr/local/bin/docker-proxy debian/docker-engine/usr/bin/docker-proxy
cp -aT /usr/local/bin/docker-containerd debian/docker-engine/usr/bin/docker-containerd
cp -aT /usr/local/bin/docker-containerd-shim debian/docker-engine/usr/bin/docker-containerd-shim
cp -aT /usr/local/bin/docker-containerd-ctr debian/docker-engine/usr/bin/docker-containerd-ctr
cp -aT /usr/local/bin/docker-runc debian/docker-engine/usr/bin/docker-runc
cp -aT /usr/local/bin/docker-init debian/docker-engine/usr/bin/docker-init
mkdir -p debian/docker-engine/usr/lib/docker
override_dh_installinit:

View file

@ -126,7 +126,9 @@ export DOCKER_GITCOMMIT=%{_gitcommit}
install -d $RPM_BUILD_ROOT/%{_bindir}
install -p -m 755 bundles/%{_origversion}/dynbinary-client/docker-%{_origversion} $RPM_BUILD_ROOT/%{_bindir}/docker
install -p -m 755 bundles/%{_origversion}/dynbinary-daemon/dockerd-%{_origversion} $RPM_BUILD_ROOT/%{_bindir}/dockerd
install -p -m 755 bundles/%{_origversion}/dynbinary-daemon/docker-proxy-%{_origversion} $RPM_BUILD_ROOT/%{_bindir}/docker-proxy
# install proxy
install -p -m 755 /usr/local/bin/docker-proxy $RPM_BUILD_ROOT/%{_bindir}/docker-proxy
# install containerd
install -p -m 755 /usr/local/bin/docker-containerd $RPM_BUILD_ROOT/%{_bindir}/docker-containerd
@ -136,6 +138,9 @@ install -p -m 755 /usr/local/bin/docker-containerd-ctr $RPM_BUILD_ROOT/%{_bindir
# install runc
install -p -m 755 /usr/local/bin/docker-runc $RPM_BUILD_ROOT/%{_bindir}/docker-runc
# install grimes
install -p -m 755 /usr/local/bin/docker-init $RPM_BUILD_ROOT/%{_bindir}/docker-init
# install udev rules
install -d $RPM_BUILD_ROOT/%{_sysconfdir}/udev/rules.d
install -p -m 644 contrib/udev/80-docker.rules $RPM_BUILD_ROOT/%{_sysconfdir}/udev/rules.d/80-docker.rules

View file

@ -9,8 +9,5 @@ set -e
export BINARY_SHORT_NAME="$DOCKER_DAEMON_BINARY_NAME"
export SOURCE_PATH='./cmd/dockerd'
source "${MAKEDIR}/.binary"
export BINARY_SHORT_NAME="$DOCKER_PROXY_BINARY_NAME"
export SOURCE_PATH='./vendor/src/github.com/docker/libnetwork/cmd/proxy'
source "${MAKEDIR}/.binary"
copy_binaries "$DEST" 'hash'
)

View file

@ -73,8 +73,8 @@ set -e
EOF
cat >> "$DEST/$version/Dockerfile.build" <<-EOF
# Install runc and containerd
RUN ./hack/dockerfile/install-binaries.sh runc-dynamic containerd-dynamic
# Install runc, containerd, proxy and grimes
RUN ./hack/dockerfile/install-binaries.sh runc-dynamic containerd-dynamic proxy grimes
EOF
if [ "$DOCKER_EXPERIMENTAL" ]; then

View file

@ -93,8 +93,8 @@ set -e
EOF
cat >> "$DEST/$version/Dockerfile.build" <<-EOF
# Install runc and containerd
RUN ./hack/dockerfile/install-binaries.sh runc-dynamic containerd-dynamic
# Install runc, containerd, proxy and grimes
RUN ./hack/dockerfile/install-binaries.sh runc-dynamic containerd-dynamic proxy grimes
EOF
if [ "$DOCKER_EXPERIMENTAL" ]; then

View file

@ -9,8 +9,4 @@ set -e
export BUILDFLAGS=( "${BUILDFLAGS[@]/netgo /}" ) # disable netgo, since we don't need it for a dynamic binary
export BUILDFLAGS=( "${BUILDFLAGS[@]/static_build /}" ) # we're not building a "static" binary here
source "${MAKEDIR}/.binary"
export BINARY_SHORT_NAME='docker-proxy'
export SOURCE_PATH='./vendor/src/github.com/docker/libnetwork/cmd/proxy'
export LDFLAGS_STATIC_DOCKER='-linkmode=external'
source "${MAKEDIR}/.binary"
)

View file

@ -1,67 +0,0 @@
package main
import (
"flag"
"fmt"
"log"
"net"
"os"
"os/signal"
"syscall"
)
func main() {
f := os.NewFile(3, "signal-parent")
host, container := parseHostContainerAddrs()
p, err := NewProxy(host, container)
if err != nil {
fmt.Fprintf(f, "1\n%s", err)
f.Close()
os.Exit(1)
}
go handleStopSignals(p)
fmt.Fprint(f, "0\n")
f.Close()
// Run will block until the proxy stops
p.Run()
}
// parseHostContainerAddrs parses the flags passed on reexec to create the TCP or UDP
// net.Addrs to map the host and container ports
func parseHostContainerAddrs() (host net.Addr, container net.Addr) {
var (
proto = flag.String("proto", "tcp", "proxy protocol")
hostIP = flag.String("host-ip", "", "host ip")
hostPort = flag.Int("host-port", -1, "host port")
containerIP = flag.String("container-ip", "", "container ip")
containerPort = flag.Int("container-port", -1, "container port")
)
flag.Parse()
switch *proto {
case "tcp":
host = &net.TCPAddr{IP: net.ParseIP(*hostIP), Port: *hostPort}
container = &net.TCPAddr{IP: net.ParseIP(*containerIP), Port: *containerPort}
case "udp":
host = &net.UDPAddr{IP: net.ParseIP(*hostIP), Port: *hostPort}
container = &net.UDPAddr{IP: net.ParseIP(*containerIP), Port: *containerPort}
default:
log.Fatalf("unsupported protocol %s", *proto)
}
return host, container
}
func handleStopSignals(p Proxy) {
s := make(chan os.Signal, 10)
signal.Notify(s, os.Interrupt, syscall.SIGTERM)
for range s {
p.Close()
os.Exit(0)
}
}

View file

@ -1,37 +0,0 @@
// docker-proxy provides a network Proxy interface and implementations for TCP
// and UDP.
package main
import (
"fmt"
"net"
)
// Proxy defines the behavior of a proxy. It forwards traffic back and forth
// between two endpoints : the frontend and the backend.
// It can be used to do software port-mapping between two addresses.
// e.g. forward all traffic between the frontend (host) 127.0.0.1:3000
// to the backend (container) at 172.17.42.108:4000.
type Proxy interface {
// Run starts forwarding traffic back and forth between the front
// and back-end addresses.
Run()
// Close stops forwarding traffic and close both ends of the Proxy.
Close()
// FrontendAddr returns the address on which the proxy is listening.
FrontendAddr() net.Addr
// BackendAddr returns the proxied address.
BackendAddr() net.Addr
}
// NewProxy creates a Proxy according to the specified frontendAddr and backendAddr.
func NewProxy(frontendAddr, backendAddr net.Addr) (Proxy, error) {
switch frontendAddr.(type) {
case *net.UDPAddr:
return NewUDPProxy(frontendAddr.(*net.UDPAddr), backendAddr.(*net.UDPAddr))
case *net.TCPAddr:
return NewTCPProxy(frontendAddr.(*net.TCPAddr), backendAddr.(*net.TCPAddr))
default:
panic(fmt.Errorf("Unsupported protocol"))
}
}

View file

@ -1,31 +0,0 @@
package main
import (
"net"
)
// StubProxy is a proxy that is a stub (does nothing).
type StubProxy struct {
frontendAddr net.Addr
backendAddr net.Addr
}
// Run does nothing.
func (p *StubProxy) Run() {}
// Close does nothing.
func (p *StubProxy) Close() {}
// FrontendAddr returns the frontend address.
func (p *StubProxy) FrontendAddr() net.Addr { return p.frontendAddr }
// BackendAddr returns the backend address.
func (p *StubProxy) BackendAddr() net.Addr { return p.backendAddr }
// NewStubProxy creates a new StubProxy
func NewStubProxy(frontendAddr, backendAddr net.Addr) (Proxy, error) {
return &StubProxy{
frontendAddr: frontendAddr,
backendAddr: backendAddr,
}, nil
}

View file

@ -1,95 +0,0 @@
package main
import (
"io"
"log"
"net"
"sync"
"syscall"
)
// TCPProxy is a proxy for TCP connections. It implements the Proxy interface to
// handle TCP traffic forwarding between the frontend and backend addresses.
type TCPProxy struct {
listener *net.TCPListener
frontendAddr *net.TCPAddr
backendAddr *net.TCPAddr
}
// NewTCPProxy creates a new TCPProxy.
func NewTCPProxy(frontendAddr, backendAddr *net.TCPAddr) (*TCPProxy, error) {
listener, err := net.ListenTCP("tcp", frontendAddr)
if err != nil {
return nil, err
}
// If the port in frontendAddr was 0 then ListenTCP will have a picked
// a port to listen on, hence the call to Addr to get that actual port:
return &TCPProxy{
listener: listener,
frontendAddr: listener.Addr().(*net.TCPAddr),
backendAddr: backendAddr,
}, nil
}
func (proxy *TCPProxy) clientLoop(client *net.TCPConn, quit chan bool) {
backend, err := net.DialTCP("tcp", nil, proxy.backendAddr)
if err != nil {
log.Printf("Can't forward traffic to backend tcp/%v: %s\n", proxy.backendAddr, err)
client.Close()
return
}
var wg sync.WaitGroup
var broker = func(to, from *net.TCPConn) {
if _, err := io.Copy(to, from); err != nil {
// If the socket we are writing to is shutdown with
// SHUT_WR, forward it to the other end of the pipe:
if err, ok := err.(*net.OpError); ok && err.Err == syscall.EPIPE {
from.CloseWrite()
}
}
to.CloseRead()
wg.Done()
}
wg.Add(2)
go broker(client, backend)
go broker(backend, client)
finish := make(chan struct{})
go func() {
wg.Wait()
close(finish)
}()
select {
case <-quit:
case <-finish:
}
client.Close()
backend.Close()
<-finish
}
// Run starts forwarding the traffic using TCP.
func (proxy *TCPProxy) Run() {
quit := make(chan bool)
defer close(quit)
for {
client, err := proxy.listener.Accept()
if err != nil {
log.Printf("Stopping proxy on tcp/%v for tcp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err)
return
}
go proxy.clientLoop(client.(*net.TCPConn), quit)
}
}
// Close stops forwarding the traffic.
func (proxy *TCPProxy) Close() { proxy.listener.Close() }
// FrontendAddr returns the TCP address on which the proxy is listening.
func (proxy *TCPProxy) FrontendAddr() net.Addr { return proxy.frontendAddr }
// BackendAddr returns the TCP proxied address.
func (proxy *TCPProxy) BackendAddr() net.Addr { return proxy.backendAddr }

View file

@ -1,168 +0,0 @@
package main
import (
"encoding/binary"
"log"
"net"
"strings"
"sync"
"syscall"
"time"
)
const (
// UDPConnTrackTimeout is the timeout used for UDP connection tracking
UDPConnTrackTimeout = 90 * time.Second
// UDPBufSize is the buffer size for the UDP proxy
UDPBufSize = 65507
)
// A net.Addr where the IP is split into two fields so you can use it as a key
// in a map:
type connTrackKey struct {
IPHigh uint64
IPLow uint64
Port int
}
func newConnTrackKey(addr *net.UDPAddr) *connTrackKey {
if len(addr.IP) == net.IPv4len {
return &connTrackKey{
IPHigh: 0,
IPLow: uint64(binary.BigEndian.Uint32(addr.IP)),
Port: addr.Port,
}
}
return &connTrackKey{
IPHigh: binary.BigEndian.Uint64(addr.IP[:8]),
IPLow: binary.BigEndian.Uint64(addr.IP[8:]),
Port: addr.Port,
}
}
type connTrackMap map[connTrackKey]*net.UDPConn
// UDPProxy is proxy for which handles UDP datagrams. It implements the Proxy
// interface to handle UDP traffic forwarding between the frontend and backend
// addresses.
type UDPProxy struct {
listener *net.UDPConn
frontendAddr *net.UDPAddr
backendAddr *net.UDPAddr
connTrackTable connTrackMap
connTrackLock sync.Mutex
}
// NewUDPProxy creates a new UDPProxy.
func NewUDPProxy(frontendAddr, backendAddr *net.UDPAddr) (*UDPProxy, error) {
listener, err := net.ListenUDP("udp", frontendAddr)
if err != nil {
return nil, err
}
return &UDPProxy{
listener: listener,
frontendAddr: listener.LocalAddr().(*net.UDPAddr),
backendAddr: backendAddr,
connTrackTable: make(connTrackMap),
}, nil
}
func (proxy *UDPProxy) replyLoop(proxyConn *net.UDPConn, clientAddr *net.UDPAddr, clientKey *connTrackKey) {
defer func() {
proxy.connTrackLock.Lock()
delete(proxy.connTrackTable, *clientKey)
proxy.connTrackLock.Unlock()
proxyConn.Close()
}()
readBuf := make([]byte, UDPBufSize)
for {
proxyConn.SetReadDeadline(time.Now().Add(UDPConnTrackTimeout))
again:
read, err := proxyConn.Read(readBuf)
if err != nil {
if err, ok := err.(*net.OpError); ok && err.Err == syscall.ECONNREFUSED {
// This will happen if the last write failed
// (e.g: nothing is actually listening on the
// proxied port on the container), ignore it
// and continue until UDPConnTrackTimeout
// expires:
goto again
}
return
}
for i := 0; i != read; {
written, err := proxy.listener.WriteToUDP(readBuf[i:read], clientAddr)
if err != nil {
return
}
i += written
}
}
}
// Run starts forwarding the traffic using UDP.
func (proxy *UDPProxy) Run() {
readBuf := make([]byte, UDPBufSize)
for {
read, from, err := proxy.listener.ReadFromUDP(readBuf)
if err != nil {
// NOTE: Apparently ReadFrom doesn't return
// ECONNREFUSED like Read do (see comment in
// UDPProxy.replyLoop)
if !isClosedError(err) {
log.Printf("Stopping proxy on udp/%v for udp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err)
}
break
}
fromKey := newConnTrackKey(from)
proxy.connTrackLock.Lock()
proxyConn, hit := proxy.connTrackTable[*fromKey]
if !hit {
proxyConn, err = net.DialUDP("udp", nil, proxy.backendAddr)
if err != nil {
log.Printf("Can't proxy a datagram to udp/%s: %s\n", proxy.backendAddr, err)
proxy.connTrackLock.Unlock()
continue
}
proxy.connTrackTable[*fromKey] = proxyConn
go proxy.replyLoop(proxyConn, from, fromKey)
}
proxy.connTrackLock.Unlock()
for i := 0; i != read; {
written, err := proxyConn.Write(readBuf[i:read])
if err != nil {
log.Printf("Can't proxy a datagram to udp/%s: %s\n", proxy.backendAddr, err)
break
}
i += written
}
}
}
// Close stops forwarding the traffic.
func (proxy *UDPProxy) Close() {
proxy.listener.Close()
proxy.connTrackLock.Lock()
defer proxy.connTrackLock.Unlock()
for _, conn := range proxy.connTrackTable {
conn.Close()
}
}
// FrontendAddr returns the UDP address on which the proxy is listening.
func (proxy *UDPProxy) FrontendAddr() net.Addr { return proxy.frontendAddr }
// BackendAddr returns the proxied UDP address.
func (proxy *UDPProxy) BackendAddr() net.Addr { return proxy.backendAddr }
func isClosedError(err error) bool {
/* This comparison is ugly, but unfortunately, net.go doesn't export errClosing.
* See:
* http://golang.org/src/pkg/net/net.go
* https://code.google.com/p/go/issues/detail?id=4337
* https://groups.google.com/forum/#!msg/golang-nuts/0_aaCvBmOcM/SptmDyX1XJMJ
*/
return strings.HasSuffix(err.Error(), "use of closed network connection")
}