Tidak yakin tentang "host kontrol" tetapi saya baru-baru ini mengikuti pembicaraan oleh para ilmuwan data yang menggunakan buruh pelabuhan untuk menjalankan skrip guna memproses beban kerja yang besar (menggunakan GPU yang dipasang di AWS) dan menampilkan hasilnya ke host. Kasus penggunaan yang sangat menarik. Pada dasarnya skrip dikemas dengan lingkungan eksekusi yang andal berkat buruh pelabuhan
KCD
@KCD Dan mengapa mereka lebih memilih kontainerisasi aplikasi melalui buruh pelabuhan daripada menggunakan wadah tingkat sistem (LXC)?
Alex Ushakov
Jawaban:
28
Itu BENAR-BENAR tergantung pada apa yang Anda butuhkan untuk skrip bash itu!
Misalnya, jika skrip bash hanya menggemakan beberapa output, Anda dapat melakukannya
docker run --rm -v $(pwd)/mybashscript.sh:/mybashscript.sh ubuntu bash /mybashscript.sh
Kemungkinan lainnya adalah Anda ingin skrip bash menginstal beberapa perangkat lunak - katakanlah skrip untuk menginstal docker-compose. Anda bisa melakukan sesuatu seperti
Tetapi pada titik ini Anda benar-benar harus mengetahui secara dekat apa yang dilakukan skrip untuk mengizinkan izin khusus yang diperlukan pada host Anda dari dalam penampung.
Saya punya ide untuk membuat container yang terhubung ke host dan membuat container baru.
Alex Ushakov
1
Docker sepertinya tidak menyukai tunggangan relatif Anda. Ini harus bekerjadocker run --rm -v $(pwd)/mybashscript.sh:/work/mybashscript.sh ubuntu /work/mybashscript.sh
KCD
5
Baris pertama memulai container ubuntu baru, dan memasang skrip di tempat yang dapat dibaca. Ini tidak mengizinkan akses penampung ke sistem file host, misalnya. Baris kedua memperlihatkan host /usr/binke penampung. Dalam kedua kasus tersebut, penampung tidak memiliki akses penuh ke sistem host. Mungkin saya salah, tapi sepertinya jawaban yang buruk untuk pertanyaan yang buruk.
Paul
3
Cukup adil- pertanyaannya cukup samar. Pertanyaannya tidak menanyakan "akses penuh ke sistem host". Seperti dijelaskan, jika skrip bash hanya dimaksudkan untuk menggemakan beberapa output, itu tidak akan MEMBUTUHKAN akses apa pun ke sistem file host. Untuk contoh kedua saya, yang menginstal docker-compose, satu-satunya izin yang Anda perlukan adalah akses ke direktori bin tempat biner disimpan. Seperti yang saya katakan di awal - untuk melakukan ini, Anda harus memiliki gagasan yang sangat spesifik tentang apa yang dilakukan skrip untuk memungkinkan izin yang tepat.
Paul Becotte
1
Mencoba ini, skrip dijalankan dalam penampung, bukan di host
All2Pie
60
Solusi yang saya gunakan adalah menyambung ke host SSHdan menjalankan perintah seperti ini:
ssh -l ${USERNAME} ${HOSTNAME} "${SCRIPT}"
MEMPERBARUI
Karena jawaban ini terus mendapatkan suara, saya ingin mengingatkan (dan sangat merekomendasikan), bahwa akun yang digunakan untuk memanggil skrip haruslah akun tanpa izin sama sekali, tetapi hanya menjalankan skrip itu sebagai sudo(itu bisa dilakukan dari sudoersfile).
Sebagai solusi lain, container dapat mengeluarkan sekumpulan perintah dan host dapat menjalankannya setelah container keluar: eval $ (docker run --rm -it container_name_to_output script)
parity3
Saya perlu menjalankan baris perintah pada Host dari dalam wadah Docker, tetapi ketika saya masuk ke dalam wadah, sshtidak ditemukan. Apakah Anda punya saran lain?
Ron Rosenfeld
@RonRosenfeld, gambar Docker mana yang Anda gunakan? dalam kasus debian / ubuntu, menjalankan ini: apt update && apt install openssh-client.
Mohammed Noureldin
Itu akan menjadi apa pun yang diinstal pada NAS Synology saya. Bagaimana saya bisa tahu?
Ron Rosenfeld
@RonRosenfeld, maaf saya tidak mengerti apa yang Anda maksud
Mohammed Noureldin
52
Menggunakan pipa bernama. Pada os host, buat skrip untuk mengulang dan membaca perintah, lalu Anda memanggil eval untuk itu.
Minta kontainer buruh pelabuhan membaca pipa bernama itu.
Untuk dapat mengakses pipa, Anda perlu memasangnya melalui volume.
Ini mirip dengan mekanisme SSH (atau metode berbasis soket serupa), tetapi membatasi Anda dengan benar ke perangkat host, yang mungkin lebih baik. Selain itu, Anda tidak perlu memberikan informasi otentikasi.
Satu-satunya peringatan saya adalah berhati-hati tentang mengapa Anda melakukan ini. Ini benar-benar sesuatu yang harus dilakukan jika Anda ingin membuat metode untuk meningkatkan sendiri dengan input pengguna atau apa pun, tetapi Anda mungkin tidak ingin memanggil perintah untuk mendapatkan beberapa data konfigurasi, karena cara yang tepat adalah meneruskannya sebagai args / volume ke buruh pelabuhan. Juga berhati-hatilah tentang fakta bahwa Anda mengelak, jadi pikirkan saja model izinnya.
Beberapa dari. Jawaban lain seperti menjalankan skrip. Di bawah volume tidak akan berfungsi secara umum karena mereka tidak akan memiliki akses ke sumber daya sistem penuh, tetapi mungkin lebih tepat tergantung pada penggunaan Anda.
PERHATIAN: Ini adalah jawaban yang benar / terbaik, dan membutuhkan lebih banyak pujian. Setiap jawaban lain adalah mengutak-atik pertanyaan "apa yang Anda coba lakukan" dan membuat pengecualian untuk beberapa hal. Saya memiliki kasus penggunaan yang sangat spesifik yang mengharuskan saya untuk dapat melakukan ini, dan ini adalah satu-satunya jawaban yang bagus imho. SSH di atas akan membutuhkan penurunan standar keamanan / firewall, dan hal-hal yang dijalankan buruh pelabuhan benar-benar salah. Terima kasih untuk ini. Saya berasumsi ini tidak mendapatkan banyak suara positif karena ini bukan jawaban salin / tempel sederhana, tetapi inilah jawabannya. +100 poin dari saya jika saya bisa
Farley
3
Bagi mereka yang mencari informasi lebih lanjut, Anda dapat menggunakan skrip berikut yang berjalan di mesin host: unix.stackexchange.com/a/369465 Tentu saja, Anda harus menjalankannya dengan 'nohup' dan membuat semacam pembungkus pengawas untuk menjaganya tetap hidup (mungkin menggunakan pekerjaan cron: P)
sucotronic
7
Ini mungkin jawaban yang bagus. Namun, akan jauh lebih baik jika Anda memberikan lebih banyak detail dan penjelasan baris perintah lagi. Apakah mungkin untuk mengelaborasi?
Mohammed Noureldin
5
Suara positif, Ini berfungsi! Buat pipa bernama menggunakan 'mkfifo host_executor_queue' tempat volume dipasang. Kemudian untuk menambahkan konsumen yang menjalankan perintah yang dimasukkan ke dalam antrian sebagai shell host, gunakan 'tail -f host_executor_queue | SH &'. & Di akhir membuatnya berjalan di latar belakang. Terakhir untuk memasukkan perintah ke dalam antrian, gunakan 'echo touch foo> host_executor_queue' - tes ini membuat file temp foo di direktori home. Jika Anda ingin konsumen memulai pada startup sistem, letakkan '@reboot tail -f host_executor_queue | sh & 'di crontab. Cukup tambahkan jalur relatif ke host_executor_queue.
skybunk
1
Bisakah seseorang mengedit jawaban dengan kode contoh?
Lucas Pottersky
6
Jika Anda tidak khawatir tentang keamanan dan Anda hanya ingin memulai kontainer pekerja galangan pada host dari dalam kontainer pekerja galangan lain seperti OP, Anda dapat berbagi server pekerja galangan yang berjalan pada tuan rumah dengan kontainer pekerja galangan dengan membagikan soket pendengarnya.
Saat Anda menjalankan perintah docker start dalam container docker Anda, server docker yang berjalan di host Anda akan melihat permintaan dan menyediakan container saudara.
Pertimbangkan bahwa buruh pelabuhan harus dipasang di kontainer, jika tidak, Anda juga perlu memasang volume untuk biner buruh pelabuhan (misalnya /usr/bin/docker:/usr/bin/docker).
@DatGuyKaj terima kasih, saya telah mengedit jawaban saya untuk mencerminkan masalah yang diuraikan oleh sumber daya Anda.
Matt Bucci
Ini tidak menjawab pertanyaan, yaitu tentang menjalankan skrip pada host, bukan dalam wadah
Brandon
5
Jawaban ini hanyalah versi yang lebih rinci dari solusi Bradford Medeiros , yang bagi saya juga merupakan jawaban terbaik, jadi pujian diberikan kepadanya.
Dalam jawabannya, dia menjelaskan APA yang harus dilakukan ( dinamai pipa ) tetapi tidak persis BAGAIMANA melakukannya.
Saya harus mengakui bahwa saya tidak tahu apa yang dinamai pipa pada saat saya membaca solusinya. Jadi saya berjuang untuk menerapkannya (meskipun sebenarnya sangat sederhana), tetapi saya berhasil, jadi saya dengan senang hati membantu dengan menjelaskan bagaimana saya melakukannya. Jadi inti dari jawaban saya hanyalah merinci perintah yang perlu Anda jalankan untuk membuatnya berfungsi, tetapi sekali lagi, kredit diberikan kepadanya.
BAGIAN 1 - Menguji konsep pipa bernama tanpa buruh pelabuhan
Di host utama, pilih folder tempat Anda ingin meletakkan file pipa bernama Anda, misalnya /path/to/pipe/dan nama pipa, misalnya mypipe, lalu jalankan:
mkfifo /path/to/pipe/mypipe
Pipa dibuat. Tipe
ls -l /path/to/pipe/mypipe
Dan periksa hak akses dimulai dengan "p", seperti
prw-r--r-- 1 root root 0 mypipe
Sekarang jalankan:
tail -f /path/to/pipe/mypipe
Terminal sekarang menunggu data untuk dikirim ke pipa ini
Sekarang buka jendela terminal lain.
Dan kemudian jalankan:
echo "hello world" > /path/to/pipe/mypipe
Periksa terminal pertama (yang dengan tail -f), itu harus menampilkan "hello world"
BAGIAN 2 - Jalankan perintah melalui pipa
Pada penampung host, alih-alih berjalan tail -fyang hanya mengeluarkan apa pun yang dikirim sebagai masukan, jalankan perintah ini yang akan menjalankannya sebagai perintah:
eval "$(cat /path/to/pipe/mypipe)"
Kemudian, dari terminal lain, coba jalankan:
echo "ls -l" > /path/to/pipe/mypipe
Kembali ke terminal pertama dan Anda akan melihat hasil dari ls -lperintah tersebut.
BAGIAN 3 - Buatlah mendengarkan selamanya
Anda mungkin telah memperhatikan bahwa di bagian sebelumnya, tepat setelah ls -loutput ditampilkan, ia berhenti mendengarkan perintah.
while true; do eval "$(cat /path/to/pipe/mypipe)"; done
(Anda tidak dapat melakukannya)
Sekarang Anda dapat mengirim perintah dalam jumlah tak terbatas satu demi satu, semuanya akan dieksekusi, bukan hanya yang pertama.
BAGIAN 4 - Jadikan bekerja bahkan saat reboot terjadi
Satu-satunya peringatan adalah jika host harus reboot, loop "while" akan berhenti bekerja.
Untuk menangani reboot, inilah yang telah saya lakukan:
Letakkan while true; do eval "$(cat /path/to/pipe/mypipe)"; donedalam file yang disebut execpipe.shdengan #!/bin/bashsundulan
Jangan lupa untuk chmod +xitu
Tambahkan ke crontab dengan menjalankan
crontab -e
Dan kemudian menambahkan
@reboot /path/to/execpipe.sh
Pada titik ini, ujilah: reboot server Anda, dan ketika sudah kembali, gema beberapa perintah ke dalam pipa dan periksa apakah sudah dijalankan. Tentu saja, Anda tidak dapat melihat keluaran dari perintah, jadi ls -ltidak akan membantu, tetapi touch somefileakan membantu.
Pilihan lainnya adalah memodifikasi skrip untuk meletakkan output dalam sebuah file, seperti:
while true; do eval "$(cat /path/to/pipe/mypipe)" &> /somepath/output.txt; done
Sekarang Anda dapat menjalankan ls -ldan output (baik stdout dan stderr yang digunakan &>di bash) harus dalam output.txt.
BAGIAN 5 - Buatlah bekerja dengan buruh pelabuhan
Jika Anda menggunakan docker compose dan dockerfile seperti yang saya lakukan, inilah yang telah saya lakukan:
Anggaplah Anda ingin memasang folder induk mypipe seperti /hostpipedi penampung Anda
Tambahkan ini:
VOLUME /hostpipe
di file dok Anda untuk membuat titik pemasangan
Kemudian tambahkan ini:
volumes:
- /path/to/pipe:/hostpipe
di file penulisan buruh pelabuhan Anda untuk memasang / path / ke / pipa sebagai / hostpipe
Mulai ulang kontainer buruh pelabuhan Anda.
BAGIAN 6 - Pengujian
Jalankan ke kontainer buruh pelabuhan Anda:
docker exec -it <container> bash
Masuk ke folder mount dan periksa apakah Anda dapat melihat pipa:
cd /hostpipe && ls -l
Sekarang coba jalankan perintah dari dalam penampung:
PERINGATAN: Jika Anda memiliki host OSX (Mac OS) dan wadah Linux, itu tidak akan berfungsi (penjelasan di sini https://stackoverflow.com/a/43474708/10018801 dan masalah di sini https://github.com/docker / for-mac / issues / 483 ) karena implementasi pipa tidak sama, jadi apa yang Anda tulis ke dalam pipa dari Linux hanya dapat dibaca oleh Linux dan apa yang Anda tulis ke pipa dari Mac OS hanya dapat dibaca oleh Mac OS (kalimat ini mungkin tidak terlalu akurat, tetapi perlu diketahui bahwa ada masalah lintas platform).
Misalnya, ketika saya menjalankan pengaturan buruh pelabuhan di DEV dari komputer Mac OS saya, pipa bernama seperti yang dijelaskan di atas tidak berfungsi. Tetapi dalam pementasan dan produksi, saya memiliki host Linux dan wadah Linux, dan berfungsi dengan sempurna.
BAGIAN 7 - Contoh dari wadah Node.JS
Berikut adalah cara saya mengirim perintah dari node js container saya ke host utama dan mengambil hasilnya:
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);
Ini bekerja dengan baik. Bagaimana dengan keamanan? Saya ingin menggunakan ini untuk memulai / menghentikan kontainer buruh pelabuhan dari dalam kontainer yang sedang berjalan? Apakah saya hanya membuat buruh pelabuhan tanpa hak apapun kecuali untuk menjalankan perintah buruh pelabuhan?
Kristof van Woensel
4
Tulis server python server sederhana yang mendengarkan di port (katakanlah 8080), ikat port -p 8080: 8080 dengan kontainer, buat permintaan HTTP ke localhost: 8080 untuk meminta server python menjalankan skrip shell dengan popen, jalankan curl atau menulis kode untuk membuat permintaan 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 ini adalah jawaban terbaik. Menjalankan perintah sewenang-wenang di mesin host HARUS dilakukan melalui beberapa jenis API (misalnya REST). Ini adalah satu-satunya cara agar keamanan dapat ditegakkan dan proses yang berjalan dapat dikontrol dengan benar (mis. Kill, penanganan stdin, stdout, exit-code, dan sebagainya). Jika tentunya akan cantik jika API ini bisa berjalan di dalam Docker, tapi secara pribadi saya tidak keberatan untuk menjalankannya di host secara langsung.
barney765
2
Kemalasan saya membuat saya menemukan solusi termudah yang tidak dipublikasikan sebagai jawaban di sini.
Yang perlu Anda lakukan untuk mendapatkan shell penuh ke host linux Anda dari dalam container docker Anda adalah:
docker run --privileged --pid=host -it alpine:3.8 \
nsenter -t 1 -m -u -n -i sh
Penjelasan:
--privileged: memberikan izin tambahan ke container, ini memungkinkan container mendapatkan akses ke perangkat host (/ dev)
--pid = host: memungkinkan wadah untuk menggunakan pohon proses dari host Docker (VM tempat daemon Docker berjalan) utilitas nsenter: memungkinkan untuk menjalankan proses di ruang nama yang ada (blok bangunan yang menyediakan isolasi ke wadah)
nsenter (-t 1 -m -u -n -i sh) memungkinkan untuk menjalankan proses sh dalam konteks isolasi yang sama seperti proses dengan PID 1. Seluruh perintah kemudian akan menyediakan shell sh interaktif di VM
Pengaturan ini memiliki implikasi keamanan yang besar dan harus digunakan dengan hati-hati (jika ada).
Meskipun jawaban ini mungkin menyelesaikan pertanyaan OP, disarankan agar Anda menjelaskan cara kerjanya dan mengapa ini menyelesaikan masalah. Ini membantu pengembang baru memahami apa yang sedang terjadi dan cara memperbaikinya sendiri serta masalah serupa. Terima kasih telah berkontribusi!
Caleb Kleveter
1
Saya memiliki pendekatan sederhana.
Langkah 1: Pasang /var/run/docker.sock:/var/run/docker.sock (Jadi Anda akan dapat menjalankan perintah buruh pelabuhan di dalam wadah Anda)
Langkah 2: Jalankan ini di bawah di dalam wadah Anda. Bagian kuncinya di sini adalah ( --network host karena ini akan dijalankan dari konteks host)
docker run -i --rm --network host -v /opt/test.sh:/test.sh alpine: 3.7 sh /test.sh
test.sh harus berisi beberapa perintah (ifconfig, netstat dll ...) apapun yang Anda butuhkan. Sekarang Anda akan bisa mendapatkan keluaran konteks host.
Menurut dokumentasi resmi buruh pelabuhan pada jaringan yang menggunakan jaringan host, "Namun, dalam semua cara lain, seperti penyimpanan, ruang nama proses, dan ruang nama pengguna, proses tersebut diisolasi dari host." Lihat - docs.docker.com/network/network-tutorial-host
Peter Mutisya
0
Seperti yang diingatkan Marcus, buruh pelabuhan pada dasarnya adalah proses isolasi. Dimulai dengan buruh pelabuhan 1.8, Anda dapat menyalin file dua arah antara host dan wadah, lihat dokumendocker cp
@AlexUshakov: tidak mungkin. Melakukan itu akan merusak banyak keuntungan buruh pelabuhan. Jangan lakukan itu. Jangan mencobanya. Pertimbangkan kembali apa yang perlu Anda lakukan.
Anda selalu dapat, pada host, mendapatkan nilai dari beberapa variabel dalam wadah Anda, seperti myvalue=$(docker run -it ubuntu echo $PATH)dan mengujinya secara teratur di shell skrip (tentu saja, Anda akan menggunakan sesuatu selain $ PATH, hanya sekedar contoh), ketika itu adalah beberapa nilai tertentu, Anda meluncurkan skrip Anda
pengguna2915097
0
Anda dapat menggunakan konsep pipa, tetapi gunakan file pada host dan fswatch untuk mencapai tujuan menjalankan skrip pada mesin host dari kontainer buruh pelabuhan. Seperti itu (Gunakan dengan risiko Anda sendiri):
#! /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
Dalam contoh ini, di dalam wadah, kirim perintah ke / dev / command_pipe, seperti ini:
Ide isolasi adalah untuk dapat membatasi apa yang dapat dilakukan oleh aplikasi / proses / wadah (apapun sudut pandang Anda) terhadap sistem host dengan sangat jelas. Karenanya, dapat menyalin dan mengeksekusi file benar-benar akan merusak keseluruhan konsep.
Iya. Tapi terkadang perlu.
Tidak. Bukan itu masalahnya, atau Docker bukanlah hal yang tepat untuk digunakan. Apa yang harus Anda lakukan adalah mendeklarasikan antarmuka yang jelas untuk apa yang ingin Anda lakukan (misalnya memperbarui konfigurasi host), dan menulis klien / server minimal untuk melakukan hal itu dan tidak lebih. Secara umum, bagaimanapun, ini tampaknya tidak terlalu diinginkan. Dalam banyak kasus, Anda cukup memikirkan kembali pendekatan Anda dan menghapus kebutuhan itu. Docker muncul ketika pada dasarnya semuanya adalah layanan yang dapat dijangkau menggunakan beberapa protokol. Saya tidak dapat memikirkan kasus penggunaan yang tepat dari container Docker yang mendapatkan hak untuk mengeksekusi barang sewenang-wenang di host.
Saya memiliki kasus penggunaan: Saya memiliki layanan dockerized A(src di github). Dalam Arepo saya membuat hook yang tepat yang setelah perintah 'git pull' membuat image buruh pelabuhan baru dan menjalankannya (dan menghapus container lama tentunya). Berikutnya: github memiliki web-hooks yang memungkinkan pembuatan permintaan POST ke tautan titik akhir arbitrer setelah push on master. Jadi saya tidak akan membuat layanan dockerized B yang akan menjadi titik akhir itu dan yang hanya akan menjalankan 'git pull' di repo A di mesin HOST (penting: perintah 'git pull' harus dijalankan di lingkungan HOST - bukan di lingkungan B karena B tidak dapat menjalankan wadah baru A di dalam B ...)
Kamil Kiełczewski
1
Masalahnya: Saya tidak ingin ada apa pun di HOST kecuali linux, git, dan buruh pelabuhan. Dan saya ingin memiliki layanan dockerizet A dan layanan B (yang sebenarnya adalah git-push handler yang menjalankan git pull pada repo A setelah seseorang membuat git push pada master). Jadi git auto-deploy adalah kasus penggunaan yang bermasalah
Kamil Kiełczewski
@ KamilKiełczewski Saya mencoba melakukan hal yang sama, apakah Anda sudah menemukan solusinya?
pengguna871784
1
Mengatakan, "Tidak, bukan itu masalahnya" adalah berpikiran sempit dan mengasumsikan Anda tahu setiap kasus penggunaan di dunia. Kasus penggunaan kami menjalankan pengujian. Mereka perlu dijalankan di container untuk menguji lingkungan dengan benar, tetapi mengingat sifat pengujian, mereka juga perlu mengeksekusi skrip pada host.
Senica Gonzalez
1
Hanya untuk mereka yang bertanya-tanya mengapa saya meninggalkan jawaban -7: a) tidak apa-apa untuk membuat kesalahan. Saya salah. Tidak apa-apa ini didokumentasikan di sini. b) Komentar benar-benar memberikan nilai; menghapus jawaban akan menghapusnya juga. c) Ini masih memberikan kontribusi sudut pandang yang mungkin bijaksana untuk dipertimbangkan (jangan putus isolasi Anda jika Anda tidak perlu. Kadang-kadang Anda harus melakukannya).
Jawaban:
Itu BENAR-BENAR tergantung pada apa yang Anda butuhkan untuk skrip bash itu!
Misalnya, jika skrip bash hanya menggemakan beberapa output, Anda dapat melakukannya
Kemungkinan lainnya adalah Anda ingin skrip bash menginstal beberapa perangkat lunak - katakanlah skrip untuk menginstal docker-compose. Anda bisa melakukan sesuatu seperti
Tetapi pada titik ini Anda benar-benar harus mengetahui secara dekat apa yang dilakukan skrip untuk mengizinkan izin khusus yang diperlukan pada host Anda dari dalam penampung.
sumber
docker run --rm -v $(pwd)/mybashscript.sh:/work/mybashscript.sh ubuntu /work/mybashscript.sh
/usr/bin
ke penampung. Dalam kedua kasus tersebut, penampung tidak memiliki akses penuh ke sistem host. Mungkin saya salah, tapi sepertinya jawaban yang buruk untuk pertanyaan yang buruk.Solusi yang saya gunakan adalah menyambung ke host
SSH
dan menjalankan perintah seperti ini:MEMPERBARUI
Karena jawaban ini terus mendapatkan suara, saya ingin mengingatkan (dan sangat merekomendasikan), bahwa akun yang digunakan untuk memanggil skrip haruslah akun tanpa izin sama sekali, tetapi hanya menjalankan skrip itu sebagai
sudo
(itu bisa dilakukan darisudoers
file).sumber
ssh
tidak ditemukan. Apakah Anda punya saran lain?apt update && apt install openssh-client
.Menggunakan pipa bernama. Pada os host, buat skrip untuk mengulang dan membaca perintah, lalu Anda memanggil eval untuk itu.
Minta kontainer buruh pelabuhan membaca pipa bernama itu.
Untuk dapat mengakses pipa, Anda perlu memasangnya melalui volume.
Ini mirip dengan mekanisme SSH (atau metode berbasis soket serupa), tetapi membatasi Anda dengan benar ke perangkat host, yang mungkin lebih baik. Selain itu, Anda tidak perlu memberikan informasi otentikasi.
Satu-satunya peringatan saya adalah berhati-hati tentang mengapa Anda melakukan ini. Ini benar-benar sesuatu yang harus dilakukan jika Anda ingin membuat metode untuk meningkatkan sendiri dengan input pengguna atau apa pun, tetapi Anda mungkin tidak ingin memanggil perintah untuk mendapatkan beberapa data konfigurasi, karena cara yang tepat adalah meneruskannya sebagai args / volume ke buruh pelabuhan. Juga berhati-hatilah tentang fakta bahwa Anda mengelak, jadi pikirkan saja model izinnya.
Beberapa dari. Jawaban lain seperti menjalankan skrip. Di bawah volume tidak akan berfungsi secara umum karena mereka tidak akan memiliki akses ke sumber daya sistem penuh, tetapi mungkin lebih tepat tergantung pada penggunaan Anda.
sumber
Jika Anda tidak khawatir tentang keamanan dan Anda hanya ingin memulai kontainer pekerja galangan pada host dari dalam kontainer pekerja galangan lain seperti OP, Anda dapat berbagi server pekerja galangan yang berjalan pada tuan rumah dengan kontainer pekerja galangan dengan membagikan soket pendengarnya.
Silakan lihat https://docs.docker.com/engine/security/security/#docker-daemon-attack-surface dan lihat apakah toleransi risiko pribadi Anda memungkinkan hal ini untuk aplikasi khusus ini.
Anda dapat melakukan ini dengan menambahkan argumen volume berikut ke perintah mulai Anda
atau dengan membagikan /var/run/docker.sock dalam file pembuatan buruh pelabuhan Anda seperti ini:
Saat Anda menjalankan perintah docker start dalam container docker Anda, server docker yang berjalan di host Anda akan melihat permintaan dan menyediakan container saudara.
kredit: http://jpetazzo.github.io/2015/09/03/do-not-use-docker-in-docker-for-ci/
sumber
/usr/bin/docker:/usr/bin/docker
).Jawaban ini hanyalah versi yang lebih rinci dari solusi Bradford Medeiros , yang bagi saya juga merupakan jawaban terbaik, jadi pujian diberikan kepadanya.
Dalam jawabannya, dia menjelaskan APA yang harus dilakukan ( dinamai pipa ) tetapi tidak persis BAGAIMANA melakukannya.
Saya harus mengakui bahwa saya tidak tahu apa yang dinamai pipa pada saat saya membaca solusinya. Jadi saya berjuang untuk menerapkannya (meskipun sebenarnya sangat sederhana), tetapi saya berhasil, jadi saya dengan senang hati membantu dengan menjelaskan bagaimana saya melakukannya. Jadi inti dari jawaban saya hanyalah merinci perintah yang perlu Anda jalankan untuk membuatnya berfungsi, tetapi sekali lagi, kredit diberikan kepadanya.
BAGIAN 1 - Menguji konsep pipa bernama tanpa buruh pelabuhan
Di host utama, pilih folder tempat Anda ingin meletakkan file pipa bernama Anda, misalnya
/path/to/pipe/
dan nama pipa, misalnyamypipe
, lalu jalankan:Pipa dibuat. Tipe
Dan periksa hak akses dimulai dengan "p", seperti
Sekarang jalankan:
Terminal sekarang menunggu data untuk dikirim ke pipa ini
Sekarang buka jendela terminal lain.
Dan kemudian jalankan:
Periksa terminal pertama (yang dengan
tail -f
), itu harus menampilkan "hello world"BAGIAN 2 - Jalankan perintah melalui pipa
Pada penampung host, alih-alih berjalan
tail -f
yang hanya mengeluarkan apa pun yang dikirim sebagai masukan, jalankan perintah ini yang akan menjalankannya sebagai perintah:Kemudian, dari terminal lain, coba jalankan:
Kembali ke terminal pertama dan Anda akan melihat hasil dari
ls -l
perintah tersebut.BAGIAN 3 - Buatlah mendengarkan selamanya
Anda mungkin telah memperhatikan bahwa di bagian sebelumnya, tepat setelah
ls -l
output ditampilkan, ia berhenti mendengarkan perintah.Alih-alih
eval "$(cat /path/to/pipe/mypipe)"
, jalankan:(Anda tidak dapat melakukannya)
Sekarang Anda dapat mengirim perintah dalam jumlah tak terbatas satu demi satu, semuanya akan dieksekusi, bukan hanya yang pertama.
BAGIAN 4 - Jadikan bekerja bahkan saat reboot terjadi
Satu-satunya peringatan adalah jika host harus reboot, loop "while" akan berhenti bekerja.
Untuk menangani reboot, inilah yang telah saya lakukan:
Letakkan
while true; do eval "$(cat /path/to/pipe/mypipe)"; done
dalam file yang disebutexecpipe.sh
dengan#!/bin/bash
sundulanJangan lupa untuk
chmod +x
ituTambahkan ke crontab dengan menjalankan
Dan kemudian menambahkan
Pada titik ini, ujilah: reboot server Anda, dan ketika sudah kembali, gema beberapa perintah ke dalam pipa dan periksa apakah sudah dijalankan. Tentu saja, Anda tidak dapat melihat keluaran dari perintah, jadi
ls -l
tidak akan membantu, tetapitouch somefile
akan membantu.Pilihan lainnya adalah memodifikasi skrip untuk meletakkan output dalam sebuah file, seperti:
Sekarang Anda dapat menjalankan
ls -l
dan output (baik stdout dan stderr yang digunakan&>
di bash) harus dalam output.txt.BAGIAN 5 - Buatlah bekerja dengan buruh pelabuhan
Jika Anda menggunakan docker compose dan dockerfile seperti yang saya lakukan, inilah yang telah saya lakukan:
Anggaplah Anda ingin memasang folder induk mypipe seperti
/hostpipe
di penampung AndaTambahkan ini:
di file dok Anda untuk membuat titik pemasangan
Kemudian tambahkan ini:
di file penulisan buruh pelabuhan Anda untuk memasang / path / ke / pipa sebagai / hostpipe
Mulai ulang kontainer buruh pelabuhan Anda.
BAGIAN 6 - Pengujian
Jalankan ke kontainer buruh pelabuhan Anda:
Masuk ke folder mount dan periksa apakah Anda dapat melihat pipa:
Sekarang coba jalankan perintah dari dalam penampung:
Dan itu harus berhasil!
PERINGATAN: Jika Anda memiliki host OSX (Mac OS) dan wadah Linux, itu tidak akan berfungsi (penjelasan di sini https://stackoverflow.com/a/43474708/10018801 dan masalah di sini https://github.com/docker / for-mac / issues / 483 ) karena implementasi pipa tidak sama, jadi apa yang Anda tulis ke dalam pipa dari Linux hanya dapat dibaca oleh Linux dan apa yang Anda tulis ke pipa dari Mac OS hanya dapat dibaca oleh Mac OS (kalimat ini mungkin tidak terlalu akurat, tetapi perlu diketahui bahwa ada masalah lintas platform).
Misalnya, ketika saya menjalankan pengaturan buruh pelabuhan di DEV dari komputer Mac OS saya, pipa bernama seperti yang dijelaskan di atas tidak berfungsi. Tetapi dalam pementasan dan produksi, saya memiliki host Linux dan wadah Linux, dan berfungsi dengan sempurna.
BAGIAN 7 - Contoh dari wadah Node.JS
Berikut adalah cara saya mengirim perintah dari node js container saya ke host utama dan mengambil hasilnya:
sumber
Tulis server python server sederhana yang mendengarkan di port (katakanlah 8080), ikat port -p 8080: 8080 dengan kontainer, buat permintaan HTTP ke localhost: 8080 untuk meminta server python menjalankan skrip shell dengan popen, jalankan curl atau menulis kode untuk membuat permintaan 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()
sumber
Kemalasan saya membuat saya menemukan solusi termudah yang tidak dipublikasikan sebagai jawaban di sini.
Ini didasarkan pada artikel bagus oleh luc juggery .
Yang perlu Anda lakukan untuk mendapatkan shell penuh ke host linux Anda dari dalam container docker Anda adalah:
Penjelasan:
--privileged: memberikan izin tambahan ke container, ini memungkinkan container mendapatkan akses ke perangkat host (/ dev)
--pid = host: memungkinkan wadah untuk menggunakan pohon proses dari host Docker (VM tempat daemon Docker berjalan) utilitas nsenter: memungkinkan untuk menjalankan proses di ruang nama yang ada (blok bangunan yang menyediakan isolasi ke wadah)
nsenter (-t 1 -m -u -n -i sh) memungkinkan untuk menjalankan proses sh dalam konteks isolasi yang sama seperti proses dengan PID 1. Seluruh perintah kemudian akan menyediakan shell sh interaktif di VM
Pengaturan ini memiliki implikasi keamanan yang besar dan harus digunakan dengan hati-hati (jika ada).
sumber
sumber
Saya memiliki pendekatan sederhana.
Langkah 1: Pasang /var/run/docker.sock:/var/run/docker.sock (Jadi Anda akan dapat menjalankan perintah buruh pelabuhan di dalam wadah Anda)
Langkah 2: Jalankan ini di bawah di dalam wadah Anda. Bagian kuncinya di sini adalah ( --network host karena ini akan dijalankan dari konteks host)
test.sh harus berisi beberapa perintah (ifconfig, netstat dll ...) apapun yang Anda butuhkan. Sekarang Anda akan bisa mendapatkan keluaran konteks host.
sumber
Seperti yang diingatkan Marcus, buruh pelabuhan pada dasarnya adalah proses isolasi. Dimulai dengan buruh pelabuhan 1.8, Anda dapat menyalin file dua arah antara host dan wadah, lihat dokumen
docker cp
https://docs.docker.com/reference/commandline/cp/
Setelah file disalin, Anda dapat menjalankannya secara lokal
sumber
myvalue=$(docker run -it ubuntu echo $PATH)
dan mengujinya secara teratur di shell skrip (tentu saja, Anda akan menggunakan sesuatu selain $ PATH, hanya sekedar contoh), ketika itu adalah beberapa nilai tertentu, Anda meluncurkan skrip AndaAnda dapat menggunakan konsep pipa, tetapi gunakan file pada host dan fswatch untuk mencapai tujuan menjalankan skrip pada mesin host dari kontainer buruh pelabuhan. Seperti itu (Gunakan dengan risiko Anda sendiri):
Dalam contoh ini, di dalam wadah, kirim perintah ke / dev / command_pipe, seperti ini:
Di host, Anda dapat memeriksa apakah jaringan telah dibuat:
sumber
Untuk memperluas user2915097 ini respon :
Ide isolasi adalah untuk dapat membatasi apa yang dapat dilakukan oleh aplikasi / proses / wadah (apapun sudut pandang Anda) terhadap sistem host dengan sangat jelas. Karenanya, dapat menyalin dan mengeksekusi file benar-benar akan merusak keseluruhan konsep.
Tidak. Bukan itu masalahnya, atau Docker bukanlah hal yang tepat untuk digunakan. Apa yang harus Anda lakukan adalah mendeklarasikan antarmuka yang jelas untuk apa yang ingin Anda lakukan (misalnya memperbarui konfigurasi host), dan menulis klien / server minimal untuk melakukan hal itu dan tidak lebih. Secara umum, bagaimanapun, ini tampaknya tidak terlalu diinginkan. Dalam banyak kasus, Anda cukup memikirkan kembali pendekatan Anda dan menghapus kebutuhan itu. Docker muncul ketika pada dasarnya semuanya adalah layanan yang dapat dijangkau menggunakan beberapa protokol. Saya tidak dapat memikirkan kasus penggunaan yang tepat dari container Docker yang mendapatkan hak untuk mengeksekusi barang sewenang-wenang di host.
sumber
A
(src di github). DalamA
repo saya membuat hook yang tepat yang setelah perintah 'git pull' membuat image buruh pelabuhan baru dan menjalankannya (dan menghapus container lama tentunya). Berikutnya: github memiliki web-hooks yang memungkinkan pembuatan permintaan POST ke tautan titik akhir arbitrer setelah push on master. Jadi saya tidak akan membuat layanan dockerized B yang akan menjadi titik akhir itu dan yang hanya akan menjalankan 'git pull' di repo A di mesin HOST (penting: perintah 'git pull' harus dijalankan di lingkungan HOST - bukan di lingkungan B karena B tidak dapat menjalankan wadah baru A di dalam B ...)