Klonen Sie Private Git Repo mit Dockerfile

240

Ich habe diesen Code aus scheinbar verschiedenen Docker-Dateien kopiert. Hier ist meine:

FROM ubuntu

MAINTAINER Luke Crooks "[email protected]"

# Update aptitude with new repo
RUN apt-get update

# Install software 
RUN apt-get install -y git python-virtualenv

# Make ssh dir
RUN mkdir /root/.ssh/

# Copy over private key, and set permissions
ADD id_rsa /root/.ssh/id_rsa
RUN chmod 700 /root/.ssh/id_rsa
RUN chown -R root:root /root/.ssh

# Create known_hosts
RUN touch /root/.ssh/known_hosts

# Remove host checking
RUN echo "Host bitbucket.org\n\tStrictHostKeyChecking no\n" >> /root/.ssh/config

# Clone the conf files into the docker container
RUN git clone [email protected]:Pumalo/docker-conf.git /home/docker-conf

Das gibt mir den Fehler

Step 10 : RUN git clone [email protected]:Pumalo/docker-conf.git /home/docker-conf
 ---> Running in 0d244d812a54
Cloning into '/home/docker-conf'...
Warning: Permanently added 'bitbucket.org,131.103.20.167' (RSA) to the list of known hosts.
Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
2014/04/30 16:07:28 The command [/bin/sh -c git clone [email protected]:Pumalo/docker-conf.git /home/docker-conf] returned a non-zero code: 128

Ich verwende Docker-Dateien zum ersten Mal, aber nach dem, was ich gelesen (und aus Arbeitskonfigurationen entnommen) habe, kann ich nicht erkennen, warum dies nicht funktioniert.

Meine id_rsa befindet sich im selben Ordner wie meine Docker-Datei und ist eine Kopie meines lokalen Schlüssels, mit dem dieses Repo problemlos geklont werden kann.

Bearbeiten:

In meiner Docker-Datei kann ich hinzufügen:

RUN cat /root/.ssh/id_rsa

Und es druckt den richtigen Schlüssel aus, sodass ich weiß, dass er korrekt kopiert wird.

Ich habe auch versucht, das zu tun, was Noah geraten hat und lief:

RUN echo "Host bitbucket.org\n\tIdentityFile /root/.ssh/id_rsa\n\tStrictHostKeyChecking no" >> /etc/ssh/ssh_config

Das funktioniert leider auch nicht.

Crooksey
quelle

Antworten:

300

Mein Schlüssel war passwortgeschützt, was das Problem verursachte. Eine Arbeitsdatei ist jetzt unten aufgeführt (für Hilfe zukünftiger Googler).

FROM ubuntu

MAINTAINER Luke Crooks "[email protected]"

# Update aptitude with new repo
RUN apt-get update

# Install software 
RUN apt-get install -y git
# Make ssh dir
RUN mkdir /root/.ssh/

# Copy over private key, and set permissions
# Warning! Anyone who gets their hands on this image will be able
# to retrieve this private key file from the corresponding image layer
ADD id_rsa /root/.ssh/id_rsa

# Create known_hosts
RUN touch /root/.ssh/known_hosts
# Add bitbuckets key
RUN ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts

# Clone the conf files into the docker container
RUN git clone [email protected]:User/repo.git
Crooksey
quelle
11
Nur für den Fall, hier ist ein Link, der beschreibt, wie der Passwortschutz des Schlüssels entfernt wird
Thomas
82
Nur zu Ihrer Information: Nachdem Sie RUN ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts ausgeführt haben, speichert das Image dies als Ebene. Wenn jemand Ihr Bild in den Griff bekommt, kann er den Schlüssel abrufen ... selbst wenn Sie diese Datei in einer späteren Ebene löschen, kann er b / c zu Schritt 7 zurückkehren, wenn Sie sie hinzugefügt haben.
Bernie Perez
23
Danke für die hilfreiche Antwort. Aber für uns ist der Build zufällig fehlgeschlagen und nach einer Untersuchung haben wir festgestellt, dass ssh-keyscandas Standard-Timeout 5 Sekunden beträgt, das Bitbucket oft überschritten hat. ssh-keyscanmeldet nicht einmal einen Fehler. Also besser laufen RUN ssh-keyscan -T 60 bitbucket.org >> /root/.ssh/known_hosts, um sicher zu gehen.
Fluidsonic
5
Könnte jemand erklären, warum Laufen ssh-keyscanein Problem ist? Mein Verständnis ist, dass es einfach den öffentlichen Schlüssel von Github / Bitbucket ziehen wird. Welche Alternative kann verwendet werden, damit sie nicht in einer Ebene endet?
Pedro
9
@Pedro Insbesondere der Keyscan-Schritt ist überhaupt kein Problem, Sie haben eindeutig Recht. Wenn überhaupt, sollten diese öffentlichen Hostschlüssel so weit wie möglich verteilt werden. Siehe sshd (8) für Details zur known_hostsDatei. Die Leute stimmen nur zufälligen Dingen zu, wenn sie alarmierend genug klingen.
Der
99

Sie sollten einen neuen SSH-Schlüsselsatz für dieses Docker-Image erstellen, da Sie dort wahrscheinlich keinen eigenen privaten Schlüssel einbetten möchten. Damit es funktioniert, müssen Sie diesen Schlüssel zu den Bereitstellungsschlüsseln in Ihrem Git-Repository hinzufügen. Hier ist das komplette Rezept:

  1. Generieren Sie SSH-Schlüssel, mit ssh-keygen -q -t rsa -N '' -f repo-keydenen Sie Repo-Key- und Repo-key.pub-Dateien erhalten.

  2. Fügen Sie repo-key.pub zu Ihren Repository-Bereitstellungsschlüsseln hinzu.
    Gehen Sie auf GitHub zu [Ihrem Repository] -> Einstellungen -> Schlüssel bereitstellen

  3. Fügen Sie Ihrer Docker-Datei so etwas hinzu:

    Repo-Schlüssel hinzufügen /
    LAUF \
      chmod 600 / repo-key && \  
      Echo "IdentityFile / Repo-Key" >> / etc / ssh / ssh_config && \  
      echo -e "StrictHostKeyChecking no" >> / etc / ssh / ssh_config && \  
      // deine git clone befehle hier ...
    

Beachten Sie, dass oben StrictHostKeyChecking deaktiviert ist, sodass Sie keine .ssh / unknown_hosts benötigen. Obwohl mir die Lösung mit ssh-keyscan in einer der obigen Antworten wahrscheinlich besser gefällt.

Marcin R.
quelle
6
Warnung: In meiner Konfiguration gibt echo -e "..." auch -e in die Datei ein. Entfernen Sie einfach die Flagge und es funktioniert gut.
Conchylicultor
Ihre Antwort war absolut perfekt, um mir bei der Lösung meines Problems zu helfen. Danke dir!
David Pointer
Ich habe immer noch das gleiche Problem:fatal: Could not read from remote repository.
Alex
1
Vielen Dank Millionen! Ich bin kurz davor, dir Liebe zu erklären. Sie haben ein Problem gelöst, mit dem ich tagelang gekämpft habe!
Alexandra
Die für diese Frage ausgewählte Antwort ist keine gute Antwort mehr. Es war 2014 richtig, aber für 2020 ist dies die richtige Antwort.
Bikal Basnet
70

Es ist nicht nötig, mit SSH-Konfigurationen herumzuspielen. Verwenden Sie eine Konfigurationsdatei (keine Docker-Datei), die Umgebungsvariablen enthält, und lassen Sie Ihre Docker-Datei zur Laufzeit von einem Shell-Skript aktualisieren. Sie halten Token von Ihren Docker-Dateien fern und können über https klonen (keine Notwendigkeit, SSH-Schlüssel zu generieren oder weiterzugeben).

Gehen Sie zu Einstellungen> Persönliche Zugriffstoken

  • Generieren Sie ein persönliches Zugriffstoken mit repoaktiviertem Gültigkeitsbereich.
  • Klon wie folgt: git clone https://[email protected]/user-or-org/repo

Einige Kommentatoren haben festgestellt, dass bei Verwendung einer freigegebenen Docker-Datei Ihr Zugriffsschlüssel anderen Personen in Ihrem Projekt zugänglich gemacht werden kann. Dies kann für Ihren speziellen Anwendungsfall von Belang sein oder auch nicht. Hier sind einige Möglichkeiten, wie Sie damit umgehen können:

  • Verwenden Sie ein Shell-Skript, um Argumente zu akzeptieren, die Ihren Schlüssel als Variable enthalten könnten. Ersetzen Sie eine Variable in Ihrer Docker-Datei durch sedoder eine ähnliche Variable , dh rufen Sie das Skript auf, durch sh rundocker.sh MYTOKEN=foodas on ersetzt werden soll https://{{MY_TOKEN}}@github.com/user-or-org/repo. Beachten Sie, dass Sie auch eine Konfigurationsdatei (in .yml oder einem beliebigen Format) verwenden können, um dasselbe zu tun, jedoch mit Umgebungsvariablen.
  • Erstellen Sie einen Github-Benutzer (und generieren Sie ein Zugriffstoken für) nur für dieses Projekt
Calvin Froedge
quelle
Für welchen Kontext sprechen Sie Settings > Applications?
Turboladen
1
Der Nachteil dieses Ansatzes besteht darin, dass Sie Anmeldeinformationen für ein privates Repo in der Docker-Datei speichern, im Gegensatz zu @ crookseys Ansatz, mit dem Sie auf einen Schlüssel verweisen können, der separat von einer Docker-Datei gespeichert ist. Ohne Kontext darüber, wie OP die Docker-Datei speichert, können wir nicht feststellen, ob dies ein Problem verursachen würde, aber aus persönlicher Erfahrung möchte ich meine Docker-Dateien in einem VCS speichern und möchte nichts festschreiben, das Anmeldeinformationen enthält. Sobald Docker die Fähigkeit implementiert hat, env-Variablen an den Build-Befehl zu übergeben, stimme ich zu, dass dies die sauberste Lösung wäre.
Jabbslad
2
@CalvinFroedge von vor Ort Ich nehme an, Sie meinen Ihren Gastgeber? Mir ist keine Möglichkeit bekannt, Umgebungsvariablen auf dem Host zur Erstellungszeit einem Container auszusetzen, weshalb wir offene Probleme wie dieses haben: github.com/docker/docker/issues/6822 . Bitte können Sie klarstellen?
Jabbslad
1
Noch sauberer (Trennung von Bedenken): ein verknüpftes Volume für das geklonte Repo + ein dedizierter Container nur für die Klonaufgabe + ein verknüpftes Volume nur mit den SSH-Schlüsseln (oder Token, wie Sie vorschlagen). Siehe stackoverflow.com/a/30992047 , möglicherweise kombiniert mit stackoverflow.com/a/29981990 .
Peterino
9
Die Frage ist auch für ein BITBUCKET-Repo, nicht für ein Github-Repo.
Michael Draper
25

Eine weitere Option ist die Verwendung eines mehrstufigen Docker-Builds, um sicherzustellen, dass Ihre SSH-Schlüssel nicht im endgültigen Image enthalten sind.

Wie in meinem Beitrag beschrieben , können Sie Ihr Zwischenbild mit den erforderlichen Abhängigkeiten zum Git-Klon und dann COPYden erforderlichen Dateien in Ihr endgültiges Bild vorbereiten .

Wenn wir LABELunsere Zwischenschichten verwenden, können wir sie sogar von der Maschine löschen, wenn wir fertig sind.

# Choose and name our temporary image.
FROM alpine as intermediate
# Add metadata identifying these images as our build containers (this will be useful later!)
LABEL stage=intermediate

# Take an SSH key as a build argument.
ARG SSH_KEY

# Install dependencies required to git clone.
RUN apk update && \
    apk add --update git && \
    apk add --update openssh

# 1. Create the SSH directory.
# 2. Populate the private key file.
# 3. Set the required permissions.
# 4. Add github to our list of known hosts for ssh.
RUN mkdir -p /root/.ssh/ && \
    echo "$SSH_KEY" > /root/.ssh/id_rsa && \
    chmod -R 600 /root/.ssh/ && \
    ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts

# Clone a repository (my website in this case)
RUN git clone [email protected]:janakerman/janakerman.git

# Choose the base image for our final image
FROM alpine

# Copy across the files from our `intermediate` container
RUN mkdir files
COPY --from=intermediate /janakerman/README.md /files/README.md

Wir können dann bauen:

MY_KEY=$(cat ~/.ssh/id_rsa)
docker build --build-arg SSH_KEY="$MY_KEY" --tag clone-example .

Beweisen Sie, dass unsere SSH-Schlüssel weg sind:

docker run -ti --rm clone-example cat /root/.ssh/id_rsa

Bereinigen Sie Zwischenbilder von der Build-Maschine:

docker rmi -f $(docker images -q --filter label=stage=intermediate)
jaker
quelle
ARG SSH_PRIVATE_KEY muss durch ARG SSH_KEY
Joseph Persie
Können wir nicht einfach die Schlüssel löschen, sobald der Git-Klon fertig ist?
Broncha
1
Sie könnten es tun, aber Sie müssten es als Teil einer einzelnen RUNtun, damit Sie den Schlüssel nicht in einer vorherigen Bildebene belassen. Ab Docker können 1.13Sie das --squash experimentelle Argument verwenden, mit dem der SSH-Schlüssel auch in Ihren endgültigen Bildebenen entfernt wird.
Baker
19

Generieren Sie für das Bitbucket-Repository ein App-Passwort (Bitbucket-Einstellungen -> Zugriffsverwaltung -> App-Passwort, siehe Abbildung) mit Lesezugriff auf das Repo und das Projekt.

Bitbucket-Benutzermenü

Dann ist der Befehl, den Sie verwenden sollten:

git clone https://username:[email protected]/reponame/projectname.git
Nomce
quelle
1
Am einfachsten :) Ich muss zugeben, dass ich einen SSH-basierten Ansatz bevorzugen würde, aber ich konnte keine der oben genannten Funktionen zum Laufen bringen ... Dateien wurden nicht gefunden usw.
Janos
Ich sehe "Access Management" nicht ... Ich denke, es ist veraltet?
Martin Thoma
1
Hat funktioniert! Schlicht und einfach ... Großartig!
Josemy
2
Natürlich ... Sie müssen nur auf Ihr Profilbild in der linken Leiste und dann auf die Bitbucket-Einstellungen klicken und Sie werden so etwas sehen: imgur.com/EI33zj3
Josemy
1
Das hat bei mir funktioniert. Ich habe jedoch Submodule und --recursivehabe nicht funktioniert. Ich musste git clonefür jedes Submodul einfügen, was in Ordnung ist, aber großartig gewesen wäre, wenn es rekursiv funktioniert hätte.
Zailyn Tamayo
12

Sie möchten häufig kein git cloneprivates Repo innerhalb des Docker-Builds ausführen . Wenn Sie den Klon dort ausführen, platzieren Sie die privaten SSH-Anmeldeinformationen im Image, wo sie später von jedem extrahiert werden können, der Zugriff auf Ihr Image hat.

Stattdessen ist es üblich, das Git-Repo von außerhalb des Dockers in das CI-Tool Ihrer Wahl und einfach COPYdie Dateien in das Image zu klonen . Dies hat einen zweiten Vorteil: Docker-Caching. Beim Docker-Caching werden der ausgeführte Befehl, die darin enthaltenen Umgebungsvariablen, Eingabedateien usw. untersucht. Wenn sie mit einem vorherigen Build aus demselben übergeordneten Schritt identisch sind, wird dieser vorherige Cache wiederverwendet. Bei einem git cloneBefehl ist der Befehl selbst identisch, sodass Docker den Cache auch dann wiederverwendet, wenn das externe Git-Repo geändert wird. Ein COPYBefehl überprüft jedoch die Dateien im Erstellungskontext und kann feststellen, ob sie identisch sind oder aktualisiert wurden. Der Cache wird nur verwendet, wenn dies angemessen ist.


Wenn Sie Ihrem Build Anmeldeinformationen hinzufügen möchten, sollten Sie dies mit einem mehrstufigen Build tun und diese Anmeldeinformationen nur in einem frühen Stadium platzieren, das niemals markiert und außerhalb Ihres Build-Hosts verschoben wird. Das Ergebnis sieht aus wie:

FROM ubuntu as clone

# Update aptitude with new repo
RUN apt-get update \
 && apt-get install -y git
# Make ssh dir
# Create known_hosts
# Add bitbuckets key
RUN mkdir /root/.ssh/ \
 && touch /root/.ssh/known_hosts \
 && ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts

# Copy over private key, and set permissions
# Warning! Anyone who gets their hands on this image will be able
# to retrieve this private key file from the corresponding image layer
COPY id_rsa /root/.ssh/id_rsa

# Clone the conf files into the docker container
RUN git clone [email protected]:User/repo.git

FROM ubuntu as release
LABEL maintainer="Luke Crooks <[email protected]>"

COPY --from=clone /repo /repo
...

In jüngerer Zeit hat BuildKit einige experimentelle Funktionen getestet, mit denen Sie einen SSH-Schlüssel als Mount übergeben können, der niemals in das Image geschrieben wird:

# syntax=docker/dockerfile:experimental
FROM ubuntu as clone
LABEL maintainer="Luke Crooks <[email protected]>"

# Update aptitude with new repo
RUN apt-get update \
 && apt-get install -y git

# Make ssh dir
# Create known_hosts
# Add bitbuckets key
RUN mkdir /root/.ssh/ \
 && touch /root/.ssh/known_hosts \
 && ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts

# Clone the conf files into the docker container
RUN --mount=type=secret,id=ssh_id,target=/root/.ssh/id_rsa \
    git clone [email protected]:User/repo.git

Und das können Sie bauen mit:

$ DOCKER_BUILDKIT=1 docker build -t your_image_name \
  --secret id=ssh_id,src=$(pwd)/id_rsa .

Beachten Sie, dass Ihr SSH-Schlüssel weiterhin nicht kennwortgeschützt sein muss. Sie können den Build jedoch zumindest in einer einzigen Phase ausführen, einen COPY-Befehl entfernen und verhindern, dass der SSH-Berechtigungsnachweis jemals Teil eines Images wird.


BuildKit hat außerdem eine Funktion nur für ssh hinzugefügt, mit der Sie Ihre passwortgeschützten ssh-Schlüssel weiterhin haben können. Das Ergebnis sieht folgendermaßen aus:

# syntax=docker/dockerfile:experimental
FROM ubuntu as clone
LABEL maintainer="Luke Crooks <[email protected]>"

# Update aptitude with new repo
RUN apt-get update \
 && apt-get install -y git

# Make ssh dir
# Create known_hosts
# Add bitbuckets key
RUN mkdir /root/.ssh/ \
 && touch /root/.ssh/known_hosts \
 && ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts

# Clone the conf files into the docker container
RUN --mount=type=ssh \
    git clone [email protected]:User/repo.git

Und das können Sie bauen mit:

$ eval $(ssh-agent)
$ ssh-add ~/.ssh/id_rsa
(Input your passphrase here)
$ DOCKER_BUILDKIT=1 docker build -t your_image_name \
  --ssh default=$SSH_AUTH_SOCK .

Dies wird wiederum in den Build eingefügt, ohne jemals in eine Bildebene geschrieben zu werden, wodurch das Risiko beseitigt wird, dass der Berechtigungsnachweis versehentlich ausläuft.


Um Docker zu zwingen, das git cloneselbst auszuführen , wenn die Zeilen zuvor zwischengespeichert wurden, können Sie ein Build-ARG einfügen, das sich mit jedem Build ändert, um den Cache zu unterbrechen. Das sieht aus wie:

# inject a datestamp arg which is treated as an environment variable and
# will break the cache for the next RUN command
ARG DATE_STAMP
# Clone the conf files into the docker container
RUN git clone [email protected]:User/repo.git

Dann fügen Sie dieses sich ändernde Argument in den Docker-Build-Befehl ein:

date_stamp=$(date +%Y%m%d-%H%M%S)
docker build --build-arg DATE_STAMP=$date_stamp .
BMitch
quelle
Sie schlagen vor, Git von außerhalb von Docker zu verwenden, erklären jedoch, wie Sie mit SSH-Schlüsseln umgehen. Wann halten Sie dies für notwendig / angemessen?
JCarlosR
1
@JCarlosR, wenn Sie kein externes System haben, auf dem der Build ausgeführt werden kann (z. B. ein CI / CD-System, das den Klon im Voraus ausführen kann). Es kann Ausnahmen geben, aber ein Klon in einer Docker-Datei ist ein Code-Geruch.
BMitch
1

Die oben genannten Lösungen funktionierten bei Bitbucket nicht. Ich dachte, das macht den Trick:

RUN ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts \
    && eval `ssh-agent` \
    && ssh-add ~/.ssh/[key] \
    && git clone [email protected]:[team]/[repo].git
tvgriek
quelle