Skip to content

Commit

Permalink
Bind mount docker.sock to wait container to use docker wait and `do…
Browse files Browse the repository at this point in the history
…cker cp`
  • Loading branch information
jessesuen committed Nov 10, 2017
1 parent 77d64a6 commit cd3a3f1
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 22 deletions.
24 changes: 23 additions & 1 deletion Dockerfile-argoexec
Original file line number Diff line number Diff line change
@@ -1,12 +1,34 @@
FROM debian:9.1

RUN apt-get update && \
apt-get install -y curl jq procps git && \
apt-get install -y curl jq procps git tar && \
rm -rf /var/lib/apt/lists/* && \
curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl && \
chmod +x ./kubectl && \
mv ./kubectl /bin/

ENV DOCKER_CHANNEL edge
ENV DOCKER_VERSION 17.10.0-ce
# TODO ENV DOCKER_SHA256
# https://github.com/docker/docker-ce/blob/5b073ee2cf564edee5adca05eee574142f7627bb/components/packaging/static/hash_files !!
# (no SHA file artifacts on download.docker.com yet as of 2017-06-07 though)

RUN set -ex; \
dockerArch='x86_64'; \
if ! curl -fL -o docker.tgz "https://download.docker.com/linux/static/${DOCKER_CHANNEL}/${dockerArch}/docker-${DOCKER_VERSION}.tgz"; then \
echo >&2 "error: failed to download 'docker-${DOCKER_VERSION}' from '${DOCKER_CHANNEL}' for '${dockerArch}'"; \
exit 1; \
fi; \
\
tar --extract \
--file docker.tgz \
--strip-components 1 \
--directory /usr/local/bin/ \
; \
rm docker.tgz; \
\
dockerd -v; \
docker -v

COPY dist/argoexec /bin/

Expand Down
2 changes: 2 additions & 0 deletions workflow/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ const (
DockerLibVolumeName = "docker-lib"
// DockerLibHostPath is the host directory path containing docker runtime state
DockerLibHostPath = "/var/lib/docker"
// DockerSockVolumeName is the volume name for the /var/run/docker.sock host path volume
DockerSockVolumeName = "docker-sock"

// AnnotationKeyNodeName is the pod metadata annotation key containing the workflow node name
AnnotationKeyNodeName = wfv1.CRDFullName + "/node-name"
Expand Down
57 changes: 36 additions & 21 deletions workflow/controller/workflowpod.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,12 @@ var (
Name: volumePodMetadata.Name,
MountPath: common.PodMetadataMountPath,
}
// volumeDockerLib provides the argoexec sidekick container access to the minion's
// docker containers runtime files (e.g. /var/lib/docker/container). This is required
// for argoexec to access the main container's logs and storage to upload output artifacts
hostPathDir = apiv1.HostPathDirectory

hostPathDir = apiv1.HostPathDirectory

// volumeDockerLib provides the wait container access to the minion's host docker containers
// runtime files (e.g. /var/lib/docker/container). This is used by the executor to access
// the main container's logs (and potentially storage to upload output artifacts)
volumeDockerLib = apiv1.Volume{
Name: common.DockerLibVolumeName,
VolumeSource: apiv1.VolumeSource{
Expand All @@ -60,6 +62,26 @@ var (
ReadOnly: true,
}

// volumeDockerSock provides the wait container direct access to the minion's host docker daemon.
// The primary purpose of this is to make available `docker cp` to collect an output artifact
// from a container. Alternatively, we could use `kubectl cp`, but `docker cp` avoids the extra
// hop to the kube api server.
volumeDockerSock = apiv1.Volume{
Name: common.DockerSockVolumeName,
VolumeSource: apiv1.VolumeSource{
HostPath: &apiv1.HostPathVolumeSource{
Path: "/var/run",
Type: &hostPathDir,
},
},
}
volumeMountDockerSock = apiv1.VolumeMount{
Name: volumeDockerSock.Name,
MountPath: "/var/run/docker.sock",
ReadOnly: true,
SubPath: "docker.sock",
}

// execEnvVars exposes various pod information as environment variables to the exec container
execEnvVars = []apiv1.EnvVar{
envFromField(common.EnvVarHostIP, "status.hostIP"),
Expand Down Expand Up @@ -134,6 +156,7 @@ func (woc *wfOperationCtx) createWorkflowPod(nodeName string, tmpl *wfv1.Templat
Volumes: []apiv1.Volume{
volumePodMetadata,
volumeDockerLib,
volumeDockerSock,
},
},
}
Expand Down Expand Up @@ -210,14 +233,10 @@ func (woc *wfOperationCtx) newWaitContainer(tmpl *wfv1.Template) (*apiv1.Contain
argoExecCmd := fmt.Sprintf(`
lineno=$(kubectl get pod $ARGO_POD_NAME -o json | jq -r '.status.containerStatuses | .[] | .name' | grep -n main | awk -F: '{print $1}')
index=$(($lineno-1))
while true ; do
kubectl get pod $ARGO_POD_NAME -o custom-columns=status:status.containerStatuses[$index].state.terminated 2>/dev/null;
if [ $? -eq 0 ] ; then
break;
fi;
echo waiting;
sleep 5;
done &&
container_id=$(kubectl get pod $ARGO_POD_NAME -o jsonpath="{.status.containerStatuses[$index].containerID}" | cut -d / -f 3-)
echo "main container_id: $container_id"
docker wait $container_id
echo "container completed"
ctrs=$(kubectl get pod $ARGO_POD_NAME -o custom-columns=:status.containerStatuses.*.name | tr "," "\n" | grep -v wait | grep -v main)
echo "sidecars: $ctrs"
for ctr in $ctrs ; do
Expand All @@ -228,6 +247,7 @@ func (woc *wfOperationCtx) newWaitContainer(tmpl *wfv1.Template) (*apiv1.Contain
ctr.VolumeMounts = []apiv1.VolumeMount{
volumeMountPodMetadata,
volumeMountDockerLib,
volumeMountDockerSock,
}
return ctr, nil
}
Expand Down Expand Up @@ -450,15 +470,10 @@ func addScriptVolume(pod *apiv1.Pod) {
ctr.Args = []string{`
lineno=$(kubectl get pod $ARGO_POD_NAME -o json | jq -r '.status.containerStatuses | .[] | .name' | grep -n main | awk -F: '{print $1}')
index=$(($lineno-1))
while true ; do
kubectl get pod $ARGO_POD_NAME -o custom-columns=status:status.containerStatuses[$index].state.terminated 2>/dev/null;
if [ $? -eq 0 ] ; then
break;
fi;
echo waiting;
sleep 5;
done &&
container_id=$(kubectl get pod $ARGO_POD_NAME -o jsonpath="{.status.containerStatuses[$index].containerID}" | cut -d / -f 3-) &&
container_id=$(kubectl get pod $ARGO_POD_NAME -o jsonpath="{.status.containerStatuses[$index].containerID}" | cut -d / -f 3-)
echo "main container_id: $container_id"
docker wait $container_id
echo "container completed"
output=$(grep stdout /var/lib/docker/containers/$container_id/*.log | jq -r '.log') &&
outputjson={\"result\":\"$output\"} &&
kubectl annotate pods $ARGO_POD_NAME --overwrite workflows.argoproj.io/outputs=${outputjson} &&
Expand Down

0 comments on commit cd3a3f1

Please sign in to comment.