Nie jestem pewien co do „hosta sterującego”, ale niedawno byłem na wykładzie naukowców zajmujących się danymi, którzy używają dockera do uruchamiania skryptów do przetwarzania dużych obciążeń (przy użyciu GPU zamontowanych na AWS) i wysyłania wyniku do hosta. Bardzo ciekawy przypadek użycia. Zasadniczo skrypty dostarczane z niezawodnym środowiskiem wykonawczym dzięki dockerowi
KCD
@KCD I dlaczego wolą konteneryzację aplikacji przez docker zamiast używania kontenerów na poziomie systemu (LXC)?
Alex Ushakov
Odpowiedzi:
30
To NAPRAWDĘ zależy od tego, do czego potrzebujesz tego skryptu bash!
Na przykład, jeśli skrypt bash po prostu wyświetla jakieś wyjście, możesz po prostu to zrobić
docker run --rm -v $(pwd)/mybashscript.sh:/mybashscript.sh ubuntu bash /mybashscript.sh
Inną możliwością jest to, że chcesz, aby skrypt bash zainstalował jakieś oprogramowanie - powiedzmy, że skrypt instaluje docker-compose. możesz zrobić coś takiego
Ale w tym momencie naprawdę zaczynasz dokładnie wiedzieć, co robi skrypt, aby zezwolić na określone uprawnienia, których potrzebuje na twoim hoście z wnętrza kontenera.
Miałem pomysł na zrobienie kontenera, który łączy się z hostem i tworzy nowe kontenery.
Alex Ushakov
1
Docker nie lubi Twojego względnego wierzchowca. To powinno działaćdocker run --rm -v $(pwd)/mybashscript.sh:/work/mybashscript.sh ubuntu /work/mybashscript.sh
KCD
5
Pierwsza linia uruchamia nowy kontener Ubuntu i montuje skrypt, w którym można go odczytać. Na przykład nie zezwala kontenerowi na dostęp do systemu plików hosta. Druga linia ujawnia hosta w /usr/binkontenerze. W żadnym przypadku kontener nie ma pełnego dostępu do systemu hosta. Może się mylę, ale wydaje się, że to zła odpowiedź na złe pytanie.
Paul
3
W porządku - pytanie było dość niejasne. Pytanie nie dotyczyło „pełnego dostępu do systemu hosta”. Zgodnie z opisem, jeśli skrypt bash ma na celu tylko echo niektórych danych wyjściowych, nie POTRZEBUJE żadnego dostępu do systemu plików hosta. W moim drugim przykładzie, który dotyczył instalacji docker-compose, jedyne potrzebne uprawnienie to dostęp do katalogu bin, w którym jest przechowywany plik binarny. Jak powiedziałem na początku - aby to zrobić, musisz mieć bardzo konkretne pomysły na temat tego, co robi skrypt, aby przyznać odpowiednie uprawnienia.
Paul Becotte
1
Próbowałem tego, skrypt jest wykonywany w kontenerze, a nie na hoście
All2Pie
62
Rozwiązaniem, którego używam, jest połączenie z hostem SSHi wykonanie następującego polecenia:
ssh -l ${USERNAME} ${HOSTNAME} "${SCRIPT}"
AKTUALIZACJA
Ponieważ ta odpowiedź wciąż zbiera głosy, chciałbym przypomnieć (i bardzo polecam), że konto, które jest używane do wywoływania skryptu, powinno być kontem bez żadnych uprawnień, a jedynie wykonywać ten skrypt jako sudo(to może być zrobione z sudoerspliku).
Jako inne obejście, kontener może wyprowadzić zestaw poleceń, a host mógłby je uruchomić po wyjściu z kontenera: eval $ (docker run --rm -it container_name_to_output script)
parity3
Muszę uruchomić wiersz poleceń na hoście z wnętrza kontenera Docker, ale kiedy wchodzę do kontenera, sshnie można go znaleźć. Czy masz jakieś inne sugestie?
Ron Rosenfeld
@RonRosenfeld, którego obrazu Dockera używasz? w przypadku Debiana / Ubuntu, uruchom to: apt update && apt install openssh-client.
Mohammed Noureldin
To byłoby wszystko, co zostało zainstalowane na moim serwerze Synology NAS. Jak mogę powiedzieć?
Ron Rosenfeld
@RonRosenfeld, przepraszam, nie rozumiem, co masz na myśli
Mohammed Noureldin
55
Użyto nazwanej potoku. W systemie operacyjnym hosta utwórz skrypt do zapętlania i odczytywania poleceń, a następnie wywołaj na nim eval.
Odczytaj kontener Dockera do tego nazwanego potoku.
Aby mieć dostęp do rury, należy ją zamontować za pomocą woluminu.
Jest to podobne do mechanizmu SSH (lub podobnej metody opartej na gnieździe), ale ogranicza cię odpowiednio do urządzenia hosta, co prawdopodobnie jest lepsze. Ponadto nie musisz przekazywać informacji uwierzytelniających.
Moje jedyne ostrzeżenie to ostrożność, dlaczego to robisz. To całkiem coś do zrobienia, jeśli chcesz stworzyć metodę samodzielnej aktualizacji z danymi wejściowymi użytkownika lub czymkolwiek, ale prawdopodobnie nie chcesz wywoływać polecenia, aby uzyskać dane konfiguracyjne, ponieważ właściwym sposobem byłoby przekazanie ich jako argumentów / volume do dockera. Uważaj również na fakt, że ewaluujesz, więc po prostu pomyśl o modelu uprawnień.
Niektóre z innych odpowiedzi, takie jak uruchomienie skryptu pod woluminem, nie będą działać ogólnie, ponieważ nie będą miały dostępu do pełnych zasobów systemowych, ale może być bardziej odpowiednie w zależności od wykorzystania.
UWAGA: To jest właściwa / najlepsza odpowiedź i wymaga trochę więcej pochwał. Każda inna odpowiedź to majstrowanie przy pytaniu „co próbujesz zrobić” i robieniu wyjątków. Mam bardzo konkretny przypadek użycia, który wymaga, abym był w stanie to zrobić, i to jest jedyna dobra odpowiedź imho. SSH powyżej wymagałoby obniżenia standardów bezpieczeństwa / zapory ogniowej, a rzeczy związane z uruchamianiem dockera są po prostu błędne. Dzięki za to. Zakładam, że to nie daje tylu głosów za, ponieważ nie jest to prosta odpowiedź typu „kopiuj / wklej”, ale to jest odpowiedź. +100 punktów ode mnie, gdybym mógł
Farley
4
Dla tych, którzy szukają więcej informacji, możesz użyć następującego skryptu działającego na maszynie hosta: unix.stackexchange.com/a/369465 Oczywiście będziesz musiał uruchomić go z 'nohup' i stworzyć coś w rodzaju opakowania nadzorcy w celu utrzymania go przy życiu (może użyć zadania cron: P)
To może być dobra odpowiedź. Byłoby jednak znacznie lepiej, gdybyś podał więcej szczegółów i więcej wyjaśnień w wierszu poleceń. Czy można to rozwinąć?
Mohammed Noureldin
5
Głosowano, to działa! Utwórz nazwany potok przy użyciu „mkfifo host_executor_queue”, w którym jest zamontowany wolumin. Następnie, aby dodać konsumenta, który wykonuje polecenia, które są umieszczane w kolejce jako powłoka hosta, użyj 'tail -f host_executor_queue | sh & '. Znak & na końcu sprawia, że działa w tle. Na koniec, aby wypchnąć polecenia do kolejki, użyj „echo touch foo> host_executor_queue” - ten test tworzy plik tymczasowy foo w katalogu domowym. Jeśli chcesz, aby konsument zaczynał przy starcie systemu, wstaw '@reboot tail -f host_executor_queue | sh & 'w crontab. Po prostu dodaj ścieżkę względną do host_executor_queue.
prycza
11
Ta odpowiedź jest po prostu bardziej szczegółową wersją rozwiązania Bradforda Medeirosa , które również dla mnie okazało się najlepszą odpowiedzią, więc zasługa jego.
W swojej odpowiedzi wyjaśnia CO robić ( nazwane rury ), ale nie dokładnie JAK to zrobić.
Muszę przyznać, że nie wiedziałem, jak nazywa się rury, kiedy czytałem jego rozwiązanie. Więc starałem się go wdrożyć (chociaż jest to naprawdę proste), ale mi się udało, więc z przyjemnością pomogę, wyjaśniając, jak to zrobiłem. Tak więc celem mojej odpowiedzi jest po prostu wyszczególnienie poleceń, które musisz uruchomić, aby działało, ale znowu zasługa jego.
CZĘŚĆ 1 - Testowanie koncepcji nazwanego potoku bez dokera
Na głównym hoście wybierz folder, w którym chcesz umieścić swój nazwany plik potoku, na przykład /path/to/pipe/i nazwę potoku mypipe, a następnie uruchom:
mkfifo /path/to/pipe/mypipe
Rura została utworzona. Rodzaj
ls -l /path/to/pipe/mypipe
I sprawdź, czy prawa dostępu zaczynają się od „p”, na przykład
prw-r--r-- 1 root root 0 mypipe
Teraz biegnij:
tail -f /path/to/pipe/mypipe
Terminal oczekuje teraz na przesłanie danych do tego potoku
Teraz otwórz kolejne okno terminala.
A potem biegnij:
echo "hello world" > /path/to/pipe/mypipe
Sprawdź pierwszy terminal (ten z tail -f), powinien wyświetlać „hello world”
CZĘŚĆ 2 - Uruchom polecenia przez potok
W kontenerze hosta, zamiast uruchamiania, tail -fktóre po prostu wyświetla wszystko, co jest wysyłane jako dane wejściowe, uruchom to polecenie, które wykona je jako polecenia:
eval "$(cat /path/to/pipe/mypipe)"
Następnie z drugiego terminala spróbuj uruchomić:
echo "ls -l" > /path/to/pipe/mypipe
Wróć do pierwszego terminala i powinieneś zobaczyć wynik ls -lpolecenia.
CZĘŚĆ 3 - Niech słucha wiecznie
Być może zauważyłeś to w poprzedniej części, zaraz po ls -l wyświetleniu wyjścia, przestaje nasłuchiwać poleceń.
Zamiast eval "$(cat /path/to/pipe/mypipe)"uruchamiać:
while true; do eval "$(cat /path/to/pipe/mypipe)"; done
(nie możesz tego zrobić)
Teraz możesz wysłać nieograniczoną liczbę poleceń jedno po drugim, wszystkie zostaną wykonane, a nie tylko pierwsze.
CZĘŚĆ 4 - Spraw, aby działało nawet po ponownym uruchomieniu
Jedynym zastrzeżeniem jest to, że jeśli host musi się zrestartować, pętla „while” przestanie działać.
Aby obsłużyć ponowne uruchomienie, oto co zrobiłem:
Umieść while true; do eval "$(cat /path/to/pipe/mypipe)"; doneplik w pliku o nazwie execpipe.shz #!/bin/bashnagłówkiem
Nie zapomnij o chmod +xtym
Dodaj go do crontab, uruchamiając
crontab -e
A potem dodawanie
@reboot /path/to/execpipe.sh
W tym momencie przetestuj to: zrestartuj serwer, a kiedy zostanie utworzony, powtórz echo niektórych poleceń w potoku i sprawdź, czy są wykonywane. Oczywiście nie możesz zobaczyć wyniku poleceń, więc ls -lnie pomoże, ale touch somefilepomoże.
Inną opcją jest zmodyfikowanie skryptu, aby umieścić dane wyjściowe w pliku, na przykład:
while true; do eval "$(cat /path/to/pipe/mypipe)" &> /somepath/output.txt; done
Teraz możesz uruchomić, ls -la dane wyjściowe (zarówno stdout, jak i stderr używane &>w bash) powinny znajdować się w output.txt.
CZĘŚĆ 5 - Spraw, by działało z dockerem
Jeśli używasz zarówno docker compose, jak i dockerfile, tak jak ja, oto co zrobiłem:
Załóżmy, że chcesz zamontować folder nadrzędny mypipe /hostpipew swoim kontenerze
Dodaj:
VOLUME /hostpipe
w pliku dockerfile, aby utworzyć punkt montowania
Następnie dodaj to:
volumes:
- /path/to/pipe:/hostpipe
w swoim pliku Docker Compose, aby zamontować / ścieżkę / do / potok jako / hostpipe
Zrestartuj kontenery Dockera.
CZĘŚĆ 6 - Testowanie
Wykonaj do swojego kontenera docker:
docker exec -it <container> bash
Przejdź do folderu montowania i sprawdź, czy widzisz rurę:
OSTRZEŻENIE: jeśli masz hosta OSX (Mac OS) i kontener Linuksa, to nie zadziała (wyjaśnienie tutaj https://stackoverflow.com/a/43474708/10018801 i wystaw tutaj https://github.com/docker / for-mac / Issues / 483 ), ponieważ implementacja potoku nie jest taka sama, więc to, co napiszesz do potoku z Linuksa, może być odczytane tylko przez Linuksa, a to, co napiszesz do potoku z Mac OS, może zostać odczytane tylko przez Mac OS (to zdanie może nie być zbyt dokładne, ale pamiętaj, że istnieje problem między platformami).
Na przykład, kiedy uruchamiam konfigurację dockera w DEV z mojego komputera z systemem Mac OS, nazwany potok, jak wyjaśniono powyżej, nie działa. Ale w przejściach i produkcji mam Linux hosta i kontenery Linuksa i działa idealnie.
CZĘŚĆ 7 - Przykład z kontenera Node.JS
Oto jak wysyłam polecenie z kontenera node js do głównego hosta i pobieram dane wyjściowe:
const pipePath = "/hostpipe/mypipe"
const outputPath = "/hostpipe/output.txt"
const commandToRun = "pwd && ls-l"
console.log("delete previous output")
if (fs.existsSync(outputPath)) fs.unlinkSync(outputPath)
console.log("writing to pipe...")
const wstream = fs.createWriteStream(pipePath)
wstream.write(commandToRun)
wstream.close()
console.log("waiting for output.txt...") //there are better ways to do that than setInterval
let timeout = 10000 //stop waiting after 10 seconds (something might be wrong)
const timeoutStart = Date.now()
const myLoop = setInterval(function () {
if (Date.now() - timeoutStart > timeout) {
clearInterval(myLoop);
console.log("timed out")
} else {
//if output.txt exists, read it
if (fs.existsSync(outputPath)) {
clearInterval(myLoop);
const data = fs.readFileSync(outputPath).toString()
if (fs.existsSync(outputPath)) fs.unlinkSync(outputPath) //delete the output file
console.log(data) //log the output of the command
}
}
}, 300);
To działa ładnie. A co z bezpieczeństwem? Chcę użyć tego do uruchamiania / zatrzymywania kontenerów Dockera z poziomu uruchomionego kontenera? Czy po prostu utworzę dockeruser bez żadnych uprawnień poza uruchamianiem poleceń docker?
Kristof van Woensel
6
Napisz prosty serwer Pythona, który nasłuchuje na porcie (powiedzmy 8080), połącz port -p 8080: 8080 z kontenerem, wyślij żądanie HTTP do localhost: 8080, aby zapytać serwer Pythona z popenem ze skryptami powłoki, uruchom curl pisanie kodu wysyłającego żądanie HTTP curl -d '{"foo": "bar"}' localhost: 8080
#!/usr/bin/pythonfrom BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer
import subprocess
import json
PORT_NUMBER = 8080# This class will handles any incoming request from# the browser classmyHandler(BaseHTTPRequestHandler):defdo_POST(self):
content_len = int(self.headers.getheader('content-length'))
post_body = self.rfile.read(content_len)
self.send_response(200)
self.end_headers()
data = json.loads(post_body)
# Use the post data
cmd = "your shell cmd"
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
p_status = p.wait()
(output, err) = p.communicate()
print"Command output : ", output
print"Command exit status/return code : ", p_status
self.wfile.write(cmd + "\n")
returntry:
# Create a web server and define the handler to manage the# incoming request
server = HTTPServer(('', PORT_NUMBER), myHandler)
print'Started httpserver on port ' , PORT_NUMBER
# Wait forever for incoming http requests
server.serve_forever()
except KeyboardInterrupt:
print'^C received, shutting down the web server'
server.socket.close()
IMO to najlepsza odpowiedź. Uruchamianie dowolnych poleceń na komputerze głównym MUSI być wykonywane przez jakiś rodzaj API (np. REST). Tylko w ten sposób można wymusić bezpieczeństwo i właściwie kontrolować uruchomione procesy (np. Zabijanie, obsługa standardowego wejścia, wyjścia standardowego, kodu wyjścia itd.). Oczywiście byłoby fajnie, gdyby to API mogło działać wewnątrz Dockera, ale osobiście nie mam nic przeciwko uruchamianiu go bezpośrednio na hoście.
barney765
6
Jeśli nie martwisz się o bezpieczeństwo i po prostu chcesz uruchomić kontener docker na hoście z innego kontenera docker, takiego jak OP, możesz udostępnić serwer docker działający na hoście z kontenerem docker, udostępniając jego gniazdo nasłuchujące.
Weź pod uwagę, że docker musi być zainstalowany w kontenerze, w przeciwnym razie będziesz musiał również zamontować wolumin dla pliku binarnego dockera (np /usr/bin/docker:/usr/bin/docker.).
Wszystko, co musisz zrobić, aby uzyskać pełną powłokę swojego hosta linuxowego z poziomu kontenera docker, to:
docker run --privileged --pid=host -it alpine:3.8 \
nsenter -t 1 -m -u -n -i sh
Wyjaśnienie:
--privileged: przyznaje dodatkowe uprawnienia do kontenera, pozwala kontenerowi uzyskać dostęp do urządzeń hosta (/ dev)
--pid = host: pozwala kontenerom na korzystanie z drzewa procesów hosta Dockera (maszyny wirtualnej, na której działa demon Docker) Narzędzie nsenter: umożliwia uruchomienie procesu w istniejących przestrzeniach nazw (elementy konstrukcyjne zapewniające izolację kontenerów)
nsenter (-t 1 -m -u -n -i sh) pozwala na uruchomienie procesu sh w tym samym kontekście izolacji co proces z PID 1. Całe polecenie zapewni wtedy interaktywną powłokę sh na maszynie wirtualnej
Ta konfiguracja ma poważne konsekwencje dla bezpieczeństwa i powinna być używana z ostrzeżeniami (jeśli istnieją).
Chociaż ta odpowiedź może rozwiązać pytanie OP, sugeruje się wyjaśnienie, jak to działa i dlaczego rozwiązuje problem. Pomaga to nowym programistom zrozumieć, co się dzieje i jak samodzielnie rozwiązać ten i podobne problemy. Dzięki za wkład!
Caleb Kleveter,
1
Mam proste podejście.
Krok 1: Zamontuj /var/run/docker.sock:/var/run/docker.sock (dzięki czemu będziesz mógł wykonywać polecenia dockera w swoim kontenerze)
Krok 2: Wykonaj to poniżej w swoim kontenerze. Kluczową częścią tutaj jest (- host sieciowy, ponieważ zostanie wykonany z kontekstu hosta)
docker run -i --rm --network host -v /opt/test.sh:/test.sh alpine: 3.7 sh /test.sh
test.sh powinien zawierać polecenia (ifconfig, netstat itd.), jakie potrzebujesz. Teraz będziesz mógł uzyskać dane wyjściowe kontekstu hosta.
Zgodnie z oficjalną dokumentacją Dockera dotyczącą pracy w sieci przy użyciu sieci hosta: „Jednak pod wszystkimi innymi względami, takimi jak przechowywanie, przestrzeń nazw procesów i przestrzeń nazw użytkowników, proces jest odizolowany od hosta”. Sprawdź - docs.docker.com/network/network-tutorial-host
Peter Mutisya
0
Jak przypomina Marcus, docker to w zasadzie izolacja procesów. Począwszy od Dockera 1.8, możesz kopiować pliki w obie strony między hostem a kontenerem, zobacz dokumentacjędocker cp
zawsze możesz na hoście pobrać wartość jakiejś zmiennej w swoim kontenerze, coś w rodzaju myvalue=$(docker run -it ubuntu echo $PATH)i testować ją regularnie w powłoce skryptu (oczywiście użyjesz czegoś innego niż $ PATH, to tylko przykład), gdy jest jakąś określoną wartością, uruchamiasz skrypt
user2915097
0
Możesz użyć koncepcji potoku, ale użyj pliku na hoście i fswatch, aby osiągnąć cel wykonania skryptu na maszynie hosta z kontenera dockera. Tak (używaj na własne ryzyko):
#! /bin/bash
touch .command_pipe
chmod +x .command_pipe
# Use fswatch to execute a command on the host machine and log result
fswatch -o --event Updated .command_pipe | \
xargs -n1 -I "{}" .command_pipe >> .command_pipe_log &
docker run -it --rm \
--name alpine \
-w /home/test \
-v $PWD/.command_pipe:/dev/command_pipe \
alpine:3.7 sh
rm -rf .command_pipe
kill %1
W tym przykładzie wewnątrz kontenera wyślij polecenia do / dev / command_pipe, na przykład:
Ideą izolacji jest możliwość bardzo wyraźnego ograniczenia tego, co aplikacja / proces / kontener (bez względu na to, z jakiego punktu widzenia) może zrobić z systemem hosta. W związku z tym możliwość skopiowania i wykonania pliku naprawdę złamałby całą koncepcję.
Tak. Ale czasami jest to konieczne.
Nie. To nie przypadek lub Docker nie jest właściwym rozwiązaniem. Powinieneś zadeklarować przejrzysty interfejs dla tego, co chcesz zrobić (np. Aktualizację konfiguracji hosta) i napisać minimalny klient / serwer, który robi dokładnie to i nic więcej. Generalnie jednak nie wydaje się to być zbyt pożądane. W wielu przypadkach powinieneś po prostu przemyśleć swoje podejście i wyeliminować tę potrzebę. Docker powstał, gdy w zasadzie wszystko było usługą osiągalną za pomocą jakiegoś protokołu. Nie przychodzi mi do głowy żaden właściwy przypadek użycia kontenera Dockera, który uzyskałby prawa do wykonywania dowolnych rzeczy na hoście.
Mam przypadek użycia: mam zdokeryzowaną usługę A(src na github). W Arepozytorium tworzę odpowiednie hooki, które po poleceniu 'git pull' tworzą nowy obraz dockera i uruchamiają go (i oczywiście usuwają stary kontener). Dalej: github ma web-hooki, które pozwalają na utworzenie żądania POST do dowolnego linku do punktu końcowego po wypchnięciu na master. Więc nie chciałbym stworzyć zdokeryzowanej usługi B, która będzie tym punktem końcowym i która będzie uruchamiała 'git pull' w repozytorium A na maszynie HOST (ważne: polecenie 'git pull' musi być wykonane w środowisku HOST - a nie w środowisku B, ponieważ B nie można uruchomić nowego kontenera A w B ...)
Kamil Kiełczewski
1
Problem: nie chcę mieć nic w HOST oprócz linux, git i docker. I chcę mieć usługę dockerizet A i usługę B (która jest w rzeczywistości programem obsługi git-push, który wykonuje git pull na repozytorium A po tym, jak ktoś wykona git push na master). Tak więc automatyczne wdrażanie gita to problematyczny przypadek użycia
Kamil Kiełczewski
@ KamilKiełczewski Próbuję zrobić dokładnie to samo, znalazłeś rozwiązanie?
user871784
1
Powiedzenie „Nie, to nie przypadek” jest ograniczeniem i zakłada, że znasz każdy przypadek użycia na świecie. Nasz przypadek użycia to przeprowadzanie testów. Muszą działać w kontenerach, aby poprawnie przetestować środowisko, ale biorąc pod uwagę charakter testów, muszą również wykonywać skrypty na hoście.
Senica Gonzalez
1
Tylko dla tych, którzy zastanawiają się, dlaczego zostawiam odpowiedź -7: a) można być omylnym. Myliłem się. W porządku, że jest to udokumentowane tutaj. b) Komentarze rzeczywiście wnoszą wartość; usunięcie odpowiedzi również je usunie. c) Nadal wnosi punkt widzenia, który może być rozsądny do rozważenia (nie przerywaj swojej izolacji, jeśli nie musisz. Czasami jednak musisz).
Odpowiedzi:
To NAPRAWDĘ zależy od tego, do czego potrzebujesz tego skryptu bash!
Na przykład, jeśli skrypt bash po prostu wyświetla jakieś wyjście, możesz po prostu to zrobić
Inną możliwością jest to, że chcesz, aby skrypt bash zainstalował jakieś oprogramowanie - powiedzmy, że skrypt instaluje docker-compose. możesz zrobić coś takiego
Ale w tym momencie naprawdę zaczynasz dokładnie wiedzieć, co robi skrypt, aby zezwolić na określone uprawnienia, których potrzebuje na twoim hoście z wnętrza kontenera.
źródło
docker run --rm -v $(pwd)/mybashscript.sh:/work/mybashscript.sh ubuntu /work/mybashscript.sh
/usr/bin
kontenerze. W żadnym przypadku kontener nie ma pełnego dostępu do systemu hosta. Może się mylę, ale wydaje się, że to zła odpowiedź na złe pytanie.Rozwiązaniem, którego używam, jest połączenie z hostem
SSH
i wykonanie następującego polecenia:AKTUALIZACJA
Ponieważ ta odpowiedź wciąż zbiera głosy, chciałbym przypomnieć (i bardzo polecam), że konto, które jest używane do wywoływania skryptu, powinno być kontem bez żadnych uprawnień, a jedynie wykonywać ten skrypt jako
sudo
(to może być zrobione zsudoers
pliku).źródło
ssh
nie można go znaleźć. Czy masz jakieś inne sugestie?apt update && apt install openssh-client
.Użyto nazwanej potoku. W systemie operacyjnym hosta utwórz skrypt do zapętlania i odczytywania poleceń, a następnie wywołaj na nim eval.
Odczytaj kontener Dockera do tego nazwanego potoku.
Aby mieć dostęp do rury, należy ją zamontować za pomocą woluminu.
Jest to podobne do mechanizmu SSH (lub podobnej metody opartej na gnieździe), ale ogranicza cię odpowiednio do urządzenia hosta, co prawdopodobnie jest lepsze. Ponadto nie musisz przekazywać informacji uwierzytelniających.
Moje jedyne ostrzeżenie to ostrożność, dlaczego to robisz. To całkiem coś do zrobienia, jeśli chcesz stworzyć metodę samodzielnej aktualizacji z danymi wejściowymi użytkownika lub czymkolwiek, ale prawdopodobnie nie chcesz wywoływać polecenia, aby uzyskać dane konfiguracyjne, ponieważ właściwym sposobem byłoby przekazanie ich jako argumentów / volume do dockera. Uważaj również na fakt, że ewaluujesz, więc po prostu pomyśl o modelu uprawnień.
Niektóre z innych odpowiedzi, takie jak uruchomienie skryptu pod woluminem, nie będą działać ogólnie, ponieważ nie będą miały dostępu do pełnych zasobów systemowych, ale może być bardziej odpowiednie w zależności od wykorzystania.
źródło
Ta odpowiedź jest po prostu bardziej szczegółową wersją rozwiązania Bradforda Medeirosa , które również dla mnie okazało się najlepszą odpowiedzią, więc zasługa jego.
W swojej odpowiedzi wyjaśnia CO robić ( nazwane rury ), ale nie dokładnie JAK to zrobić.
Muszę przyznać, że nie wiedziałem, jak nazywa się rury, kiedy czytałem jego rozwiązanie. Więc starałem się go wdrożyć (chociaż jest to naprawdę proste), ale mi się udało, więc z przyjemnością pomogę, wyjaśniając, jak to zrobiłem. Tak więc celem mojej odpowiedzi jest po prostu wyszczególnienie poleceń, które musisz uruchomić, aby działało, ale znowu zasługa jego.
CZĘŚĆ 1 - Testowanie koncepcji nazwanego potoku bez dokera
Na głównym hoście wybierz folder, w którym chcesz umieścić swój nazwany plik potoku, na przykład
/path/to/pipe/
i nazwę potokumypipe
, a następnie uruchom:Rura została utworzona. Rodzaj
I sprawdź, czy prawa dostępu zaczynają się od „p”, na przykład
Teraz biegnij:
Terminal oczekuje teraz na przesłanie danych do tego potoku
Teraz otwórz kolejne okno terminala.
A potem biegnij:
Sprawdź pierwszy terminal (ten z
tail -f
), powinien wyświetlać „hello world”CZĘŚĆ 2 - Uruchom polecenia przez potok
W kontenerze hosta, zamiast uruchamiania,
tail -f
które po prostu wyświetla wszystko, co jest wysyłane jako dane wejściowe, uruchom to polecenie, które wykona je jako polecenia:Następnie z drugiego terminala spróbuj uruchomić:
Wróć do pierwszego terminala i powinieneś zobaczyć wynik
ls -l
polecenia.CZĘŚĆ 3 - Niech słucha wiecznie
Być może zauważyłeś to w poprzedniej części, zaraz po
ls -l
wyświetleniu wyjścia, przestaje nasłuchiwać poleceń.Zamiast
eval "$(cat /path/to/pipe/mypipe)"
uruchamiać:(nie możesz tego zrobić)
Teraz możesz wysłać nieograniczoną liczbę poleceń jedno po drugim, wszystkie zostaną wykonane, a nie tylko pierwsze.
CZĘŚĆ 4 - Spraw, aby działało nawet po ponownym uruchomieniu
Jedynym zastrzeżeniem jest to, że jeśli host musi się zrestartować, pętla „while” przestanie działać.
Aby obsłużyć ponowne uruchomienie, oto co zrobiłem:
Umieść
while true; do eval "$(cat /path/to/pipe/mypipe)"; done
plik w pliku o nazwieexecpipe.sh
z#!/bin/bash
nagłówkiemNie zapomnij o
chmod +x
tymDodaj go do crontab, uruchamiając
A potem dodawanie
W tym momencie przetestuj to: zrestartuj serwer, a kiedy zostanie utworzony, powtórz echo niektórych poleceń w potoku i sprawdź, czy są wykonywane. Oczywiście nie możesz zobaczyć wyniku poleceń, więc
ls -l
nie pomoże, aletouch somefile
pomoże.Inną opcją jest zmodyfikowanie skryptu, aby umieścić dane wyjściowe w pliku, na przykład:
Teraz możesz uruchomić,
ls -l
a dane wyjściowe (zarówno stdout, jak i stderr używane&>
w bash) powinny znajdować się w output.txt.CZĘŚĆ 5 - Spraw, by działało z dockerem
Jeśli używasz zarówno docker compose, jak i dockerfile, tak jak ja, oto co zrobiłem:
Załóżmy, że chcesz zamontować folder nadrzędny mypipe
/hostpipe
w swoim kontenerzeDodaj:
w pliku dockerfile, aby utworzyć punkt montowania
Następnie dodaj to:
w swoim pliku Docker Compose, aby zamontować / ścieżkę / do / potok jako / hostpipe
Zrestartuj kontenery Dockera.
CZĘŚĆ 6 - Testowanie
Wykonaj do swojego kontenera docker:
Przejdź do folderu montowania i sprawdź, czy widzisz rurę:
Teraz spróbuj uruchomić polecenie z kontenera:
I powinno działać!
OSTRZEŻENIE: jeśli masz hosta OSX (Mac OS) i kontener Linuksa, to nie zadziała (wyjaśnienie tutaj https://stackoverflow.com/a/43474708/10018801 i wystaw tutaj https://github.com/docker / for-mac / Issues / 483 ), ponieważ implementacja potoku nie jest taka sama, więc to, co napiszesz do potoku z Linuksa, może być odczytane tylko przez Linuksa, a to, co napiszesz do potoku z Mac OS, może zostać odczytane tylko przez Mac OS (to zdanie może nie być zbyt dokładne, ale pamiętaj, że istnieje problem między platformami).
Na przykład, kiedy uruchamiam konfigurację dockera w DEV z mojego komputera z systemem Mac OS, nazwany potok, jak wyjaśniono powyżej, nie działa. Ale w przejściach i produkcji mam Linux hosta i kontenery Linuksa i działa idealnie.
CZĘŚĆ 7 - Przykład z kontenera Node.JS
Oto jak wysyłam polecenie z kontenera node js do głównego hosta i pobieram dane wyjściowe:
źródło
Napisz prosty serwer Pythona, który nasłuchuje na porcie (powiedzmy 8080), połącz port -p 8080: 8080 z kontenerem, wyślij żądanie HTTP do localhost: 8080, aby zapytać serwer Pythona z popenem ze skryptami powłoki, uruchom curl pisanie kodu wysyłającego żądanie HTTP curl -d '{"foo": "bar"}' localhost: 8080
#!/usr/bin/python from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer import subprocess import json PORT_NUMBER = 8080 # This class will handles any incoming request from # the browser class myHandler(BaseHTTPRequestHandler): def do_POST(self): content_len = int(self.headers.getheader('content-length')) post_body = self.rfile.read(content_len) self.send_response(200) self.end_headers() data = json.loads(post_body) # Use the post data cmd = "your shell cmd" p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) p_status = p.wait() (output, err) = p.communicate() print "Command output : ", output print "Command exit status/return code : ", p_status self.wfile.write(cmd + "\n") return try: # Create a web server and define the handler to manage the # incoming request server = HTTPServer(('', PORT_NUMBER), myHandler) print 'Started httpserver on port ' , PORT_NUMBER # Wait forever for incoming http requests server.serve_forever() except KeyboardInterrupt: print '^C received, shutting down the web server' server.socket.close()
źródło
Jeśli nie martwisz się o bezpieczeństwo i po prostu chcesz uruchomić kontener docker na hoście z innego kontenera docker, takiego jak OP, możesz udostępnić serwer docker działający na hoście z kontenerem docker, udostępniając jego gniazdo nasłuchujące.
Zobacz https://docs.docker.com/engine/security/security/#docker-daemon-attack-surface i sprawdź, czy Twoja osobista tolerancja ryzyka pozwala na to w tej konkretnej aplikacji.
Możesz to zrobić, dodając następujące argumenty głośności do polecenia startu
lub udostępniając /var/run/docker.sock w swoim pliku redagowania dockera w następujący sposób:
Po uruchomieniu polecenia docker start w kontenerze docker, serwer docker działający na twoim hoście zobaczy żądanie i aprowizuje kontener siostrzany.
kredyt: http://jpetazzo.github.io/2015/09/03/do-not-use-docker-in-docker-for-ci/
źródło
/usr/bin/docker:/usr/bin/docker
.).Moje lenistwo doprowadziło mnie do znalezienia najłatwiejszego rozwiązania, które nie zostało tutaj opublikowane jako odpowiedź.
Opiera się ona na wielki artykuł przez luc juggery .
Wszystko, co musisz zrobić, aby uzyskać pełną powłokę swojego hosta linuxowego z poziomu kontenera docker, to:
Wyjaśnienie:
--privileged: przyznaje dodatkowe uprawnienia do kontenera, pozwala kontenerowi uzyskać dostęp do urządzeń hosta (/ dev)
--pid = host: pozwala kontenerom na korzystanie z drzewa procesów hosta Dockera (maszyny wirtualnej, na której działa demon Docker) Narzędzie nsenter: umożliwia uruchomienie procesu w istniejących przestrzeniach nazw (elementy konstrukcyjne zapewniające izolację kontenerów)
nsenter (-t 1 -m -u -n -i sh) pozwala na uruchomienie procesu sh w tym samym kontekście izolacji co proces z PID 1. Całe polecenie zapewni wtedy interaktywną powłokę sh na maszynie wirtualnej
Ta konfiguracja ma poważne konsekwencje dla bezpieczeństwa i powinna być używana z ostrzeżeniami (jeśli istnieją).
źródło
źródło
Mam proste podejście.
Krok 1: Zamontuj /var/run/docker.sock:/var/run/docker.sock (dzięki czemu będziesz mógł wykonywać polecenia dockera w swoim kontenerze)
Krok 2: Wykonaj to poniżej w swoim kontenerze. Kluczową częścią tutaj jest (- host sieciowy, ponieważ zostanie wykonany z kontekstu hosta)
test.sh powinien zawierać polecenia (ifconfig, netstat itd.), jakie potrzebujesz. Teraz będziesz mógł uzyskać dane wyjściowe kontekstu hosta.
źródło
Jak przypomina Marcus, docker to w zasadzie izolacja procesów. Począwszy od Dockera 1.8, możesz kopiować pliki w obie strony między hostem a kontenerem, zobacz dokumentację
docker cp
https://docs.docker.com/reference/commandline/cp/
Po skopiowaniu pliku możesz uruchomić go lokalnie
źródło
myvalue=$(docker run -it ubuntu echo $PATH)
i testować ją regularnie w powłoce skryptu (oczywiście użyjesz czegoś innego niż $ PATH, to tylko przykład), gdy jest jakąś określoną wartością, uruchamiasz skryptMożesz użyć koncepcji potoku, ale użyj pliku na hoście i fswatch, aby osiągnąć cel wykonania skryptu na maszynie hosta z kontenera dockera. Tak (używaj na własne ryzyko):
W tym przykładzie wewnątrz kontenera wyślij polecenia do / dev / command_pipe, na przykład:
Na hoście możesz sprawdzić, czy sieć została utworzona:
źródło
Aby rozwinąć na user2915097 męska odpowiedzi :
Ideą izolacji jest możliwość bardzo wyraźnego ograniczenia tego, co aplikacja / proces / kontener (bez względu na to, z jakiego punktu widzenia) może zrobić z systemem hosta. W związku z tym możliwość skopiowania i wykonania pliku naprawdę złamałby całą koncepcję.
Nie. To nie przypadek lub Docker nie jest właściwym rozwiązaniem. Powinieneś zadeklarować przejrzysty interfejs dla tego, co chcesz zrobić (np. Aktualizację konfiguracji hosta) i napisać minimalny klient / serwer, który robi dokładnie to i nic więcej. Generalnie jednak nie wydaje się to być zbyt pożądane. W wielu przypadkach powinieneś po prostu przemyśleć swoje podejście i wyeliminować tę potrzebę. Docker powstał, gdy w zasadzie wszystko było usługą osiągalną za pomocą jakiegoś protokołu. Nie przychodzi mi do głowy żaden właściwy przypadek użycia kontenera Dockera, który uzyskałby prawa do wykonywania dowolnych rzeczy na hoście.
źródło
A
(src na github). WA
repozytorium tworzę odpowiednie hooki, które po poleceniu 'git pull' tworzą nowy obraz dockera i uruchamiają go (i oczywiście usuwają stary kontener). Dalej: github ma web-hooki, które pozwalają na utworzenie żądania POST do dowolnego linku do punktu końcowego po wypchnięciu na master. Więc nie chciałbym stworzyć zdokeryzowanej usługi B, która będzie tym punktem końcowym i która będzie uruchamiała 'git pull' w repozytorium A na maszynie HOST (ważne: polecenie 'git pull' musi być wykonane w środowisku HOST - a nie w środowisku B, ponieważ B nie można uruchomić nowego kontenera A w B ...)