डॉकटर कंटेनर से होस्ट को कैसे नियंत्रित करें?
उदाहरण के लिए, होस्ट स्क्रिप्ट को होस्ट करने के लिए प्रतिलिपि कैसे निष्पादित करें?
डॉकटर कंटेनर से होस्ट को कैसे नियंत्रित करें?
उदाहरण के लिए, होस्ट स्क्रिप्ट को होस्ट करने के लिए प्रतिलिपि कैसे निष्पादित करें?
जवाबों:
यह वास्तव में निर्भर करता है कि आपको उस बैश स्क्रिप्ट की क्या आवश्यकता है!
उदाहरण के लिए, यदि बैश स्क्रिप्ट बस कुछ आउटपुट देती है, तो आप बस कर सकते हैं
docker run --rm -v $(pwd)/mybashscript.sh:/mybashscript.sh ubuntu bash /mybashscript.sh
एक और संभावना यह है कि आप चाहते हैं कि बैश स्क्रिप्ट कुछ सॉफ़्टवेयर स्थापित करे- स्क्रिप्ट को डॉकटर-कंपोज़ स्थापित करने के लिए कहें। आप कुछ ऐसा कर सकते हैं
docker run --rm -v /usr/bin:/usr/bin --privileged -v $(pwd)/mybashscript.sh:/mybashscript.sh ubuntu bash /mybashscript.sh
लेकिन इस बिंदु पर आप वास्तव में अंतरंग रूप से यह जानने में जुटे हैं कि कंटेनर के अंदर से आपके मेजबान को इसकी विशिष्ट अनुमति के लिए स्क्रिप्ट क्या कर रही है।
docker run --rm -v $(pwd)/mybashscript.sh:/work/mybashscript.sh ubuntu /work/mybashscript.sh
/usr/binकंटेनर में मेजबान की उजागर करती है । न तो मामले में कंटेनर में मेजबान सिस्टम की पूरी पहुंच होती है। शायद मैं गलत हूं, लेकिन यह एक बुरे सवाल के बुरे जवाब की तरह लगता है।
मैं जिस समाधान का उपयोग करता हूं, वह मेजबान से कनेक्ट करने SSHऔर कमांड को इस तरह निष्पादित करने के लिए है:
ssh -l ${USERNAME} ${HOSTNAME} "${SCRIPT}"
जैसा कि यह जवाब वोटों को प्राप्त करता रहता है, मैं याद दिलाना चाहता हूं (और अत्यधिक अनुशंसा करता हूं), कि स्क्रिप्ट को लागू करने के लिए जिस खाते का उपयोग किया जा रहा है, वह एक खाता होना चाहिए जिसमें कोई अनुमति नहीं है, लेकिन केवल उस स्क्रिप्ट को निष्पादित करना sudo(जो कि हो सकता है) sudoersफ़ाइल से किया गया )।
sshतो नहीं मिलता है। आपके पास कोई और सुझाव है?
apt update && apt install openssh-client:।
एक नामित पाइप का इस्तेमाल किया। होस्ट ओएस पर, लूप पर एक स्क्रिप्ट बनाएं और कमांड पढ़ें, और फिर आप उस पर eval कहते हैं।
क्या डॉकटर कंटेनर को उस नामित पाइप से पढ़ा जाता है।
पाइप तक पहुंचने में सक्षम होने के लिए, आपको इसे वॉल्यूम के माध्यम से माउंट करने की आवश्यकता है।
यह एसएसएच तंत्र (या समान सॉकेट आधारित विधि) के समान है, लेकिन आपको मेजबान डिवाइस के लिए ठीक से प्रतिबंधित करता है, जो संभवतः बेहतर है। साथ ही आपको प्रमाणीकरण जानकारी के आसपास से गुजरना नहीं पड़ता है।
मेरी एकमात्र चेतावनी आपको इस बारे में सतर्क रहना है कि आप ऐसा क्यों कर रहे हैं। यह पूरी तरह से कुछ है यदि आप उपयोगकर्ता इनपुट या जो कुछ भी करने के लिए स्वयं अपग्रेड करने के लिए एक विधि बनाना चाहते हैं, लेकिन आप शायद कुछ कॉन्फिग डेटा प्राप्त करने के लिए एक कमांड को कॉल नहीं करना चाहते हैं, जैसा कि उचित तरीका है कि आर्ग्स में पास करना / कर्ता में मात्रा। इस तथ्य के बारे में भी सतर्क रहें कि आप विकसित हो रहे हैं, इसलिए केवल अनुमति मॉडल को एक विचार दें।
कुछ अन्य जवाब। जैसे कि स्क्रिप्ट चलाना। कोई वॉल्यूम सामान्य रूप से काम नहीं करेगा क्योंकि उनके पास पूर्ण सिस्टम संसाधनों तक पहुंच नहीं होगी, लेकिन यह आपके उपयोग के आधार पर अधिक उपयुक्त हो सकता है।
यदि आप सुरक्षा के बारे में चिंतित नहीं हैं और आप ओपी जैसे किसी अन्य डॉकटर कंटेनर के भीतर से होस्ट पर एक डॉक कंटेनर शुरू करना चाहते हैं, तो आप डॉक कंटेनर में होस्ट पर चलने वाले डॉक सर्वर को साझा कर सकते हैं इसे सॉकेट सुन सकते हैं।
कृपया देखें https://docs.docker.com/engine/security/security/#docker-daemon-attack-surface देखें और देखें कि क्या आपकी व्यक्तिगत जोखिम सहिष्णुता इस विशेष एप्लिकेशन के लिए अनुमति देती है।
आप अपने आरंभ कमांड में निम्न वॉल्यूम आर्गन जोड़कर ऐसा कर सकते हैं
docker run -v /var/run/docker.sock:/var/run/docker.sock ...
या अपने docker में इस तरह फ़ाइल लिखें /var/run/docker.sock साझा करके:
version: '3'
services:
ci:
command: ...
image: ...
volumes
- /var/run/docker.sock:/var/run/docker.sock
जब आप docker start कमांड को अपने docker कंटेनर के भीतर चलाते हैं, तो आपके host पर चलने वाले docker सर्वर रिक्वेस्ट को देखेंगे और sibre कंटेनर को प्रोविजन करेंगे।
साभार : http://jpetazzo.github.io/2015/09/03/do-not-use-docker-in-docker-for-ci/
/usr/bin/docker:/usr/bin/docker) के लिए एक वॉल्यूम माउंट करने की आवश्यकता होगी ।
यह उत्तर ब्रैडफोर्ड मेडीयरोस के समाधान का एक अधिक विस्तृत संस्करण है , जो मेरे लिए सबसे अच्छा जवाब है, इसलिए इसका श्रेय उन्हें जाता है।
अपने जवाब में, वह WHAT को करने के लिए ( नामित पाइप) बताते हैं ) लेकिन इसे करने के लिए बिल्कुल कैसे नहीं।
मुझे स्वीकार करना होगा कि मुझे नहीं पता था कि उस समय पाइप का नाम क्या है जब मैंने उसका समाधान पढ़ा। इसलिए मैंने इसे लागू करने के लिए संघर्ष किया (जबकि यह वास्तव में सरल है), लेकिन मैं सफल रहा, इसलिए मैं यह बताकर खुश हूं कि मैं यह कैसे करूं। तो मेरे जवाब की बात यह है कि इसे काम करने के लिए आपको केवल उन कमांड का विस्तार करना है, जिन्हें चलाने की जरूरत है, लेकिन फिर से, क्रेडिट उनके पास जाता है।
मुख्य होस्ट पर, उस फ़ोल्डर को चुना जहाँ आप अपनी नामित पाइप फ़ाइल, उदाहरण के लिए /path/to/pipe/और पाइप का नाम, उदाहरण के लिए mypipe, और उसके बाद रखना चाहते हैं:
mkfifo /path/to/pipe/mypipe
पाइप बनाया जाता है। प्रकार
ls -l /path/to/pipe/mypipe
और एक्सेस अधिकारों की जांच "पी" से शुरू करें, जैसे कि
prw-r--r-- 1 root root 0 mypipe
अब चलाएं:
tail -f /path/to/pipe/mypipe
टर्मिनल अब इस पाइप में डेटा भेजे जाने की प्रतीक्षा कर रहा है
अब एक और टर्मिनल विंडो खोलें।
और फिर चलाएं:
echo "hello world" > /path/to/pipe/mypipe
पहले टर्मिनल (एक के साथ tail -f) की जांच करें, इसे "हैलो वर्ल्ड" प्रदर्शित करना चाहिए
होस्ट कंटेनर पर, रनिंग के बजाय tail -fजो इनपुट के रूप में भेजे गए आउटपुट को आउटपुट करता है, इस कमांड को चलाएं जो इसे कमांड के रूप में निष्पादित करेगा:
eval "$(cat /path/to/pipe/mypipe)"
फिर, दूसरे टर्मिनल से, चलाने का प्रयास करें:
echo "ls -l" > /path/to/pipe/mypipe
पहले टर्मिनल पर वापस जाएं और आपको ls -lकमांड का परिणाम देखना चाहिए ।
आपने देखा होगा कि पिछले भाग में, ls -lआउटपुट प्रदर्शित होने के ठीक बाद , यह कमांड्स के लिए सुनना बंद कर देता है।
इसके बजाय eval "$(cat /path/to/pipe/mypipe)", भागो:
while true; do eval "$(cat /path/to/pipe/mypipe)"; done
(आप कह सकते हैं कि)
अब आप एक के बाद एक असीमित संख्या में आदेश भेज सकते हैं, वे सभी निष्पादित होंगे, न कि केवल पहले एक।
एकमात्र चेतावनी है यदि मेजबान को रिबूट करना है, तो "जबकि" लूप काम करना बंद कर देगा।
रिबूट को संभालने के लिए, यहाँ मैंने क्या किया है:
हेडर के साथ while true; do eval "$(cat /path/to/pipe/mypipe)"; doneएक फ़ाइल में रखोexecpipe.sh#!/bin/bash
chmod +xइसे मत भूलना
इसे दौड़ने के साथ क्रस्टैब में जोड़ें
crontab -e
और फिर जोड़ना
@reboot /path/to/execpipe.sh
इस बिंदु पर, इसका परीक्षण करें: अपने सर्वर को रिबूट करें, और जब यह वापस आ जाता है, तो पाइप में कुछ कमांड को गूंजें और जांच करें कि क्या वे निष्पादित हैं। बेशक, आप कमांड का आउटपुट देखने में सक्षम नहीं हैं, इसलिए ls -lमदद नहीं करेगा, लेकिन touch somefileमदद करेगा।
एक अन्य विकल्प यह है कि आउटपुट को किसी फ़ाइल में डालने के लिए स्क्रिप्ट को संशोधित किया जाए, जैसे:
while true; do eval "$(cat /path/to/pipe/mypipe)" &> /somepath/output.txt; done
अब आप रन कर सकते हैं ls -lऔर आउटपुट ( &>बैश में स्टैडआउट और स्टेडर दोनों ) output.txt में होना चाहिए।
यदि आप docker कंपोज़ और dockerfile दोनों का उपयोग कर रहे हैं जैसे मैं करता हूँ, यहाँ मैंने किया है:
मान लें कि आप /hostpipeअपने कंटेनर में mypipe के मूल फ़ोल्डर को माउंट करना चाहते हैं
इसे जोड़ो:
VOLUME /hostpipe
माउंट बिंदु बनाने के लिए अपने डॉकफाइल में
फिर इसे जोड़ें:
volumes:
- /path/to/pipe:/hostpipe
अपने docker में / hostpipe के रूप में / path / to / पाइप को माउंट करने के लिए फ़ाइल लिखें
अपने डॉकटर कंटेनरों को पुनः आरंभ करें।
अपने डॉकटर कंटेनर में जाएं:
docker exec -it <container> bash
माउंट फ़ोल्डर में जाएं और जांचें कि आप पाइप देख सकते हैं:
cd /hostpipe && ls -l
अब कंटेनर के भीतर से कमांड चलाने का प्रयास करें:
echo "touch this_file_was_created_on_main_host_from_a_container.txt" > /hostpipe/mypipe
और यह काम करना चाहिए!
चेतावनी: यदि आपके पास एक OSX (मैक ओएस) होस्ट और एक लिनक्स कंटेनर है, तो यह काम नहीं करेगा (स्पष्टीकरण यहाँ https://stackoverflow.com/a/43474708/10018801 और यहाँ जारी करें https://github.com/docker के लिए-मैक / / मुद्दों / 483 ) क्योंकि पाइप कार्यान्वयन समान नहीं है, इसलिए आप लिनक्स से पाइप में जो लिखते हैं उसे केवल लिनक्स द्वारा पढ़ा जा सकता है और मैक ओएस से पाइप में आप जो लिखते हैं वह केवल एक द्वारा पढ़ा जा सकता है मैक ओएस (यह वाक्य बहुत सटीक नहीं हो सकता है, लेकिन बस एक क्रॉस-प्लेटफ़ॉर्म समस्या मौजूद है)।
उदाहरण के लिए, जब मैं अपने मैक ओएस कंप्यूटर से डीईवी में अपना डॉकटर सेटअप चलाता हूं, तो ऊपर दिया गया नाम का पाइप काम नहीं करता है। लेकिन मंचन और उत्पादन में, मेरे पास लिनक्स होस्ट और लिनक्स कंटेनर हैं, और यह पूरी तरह से काम करता है।
यहां बताया गया है कि मैं अपने नोड js कंटेनर से मुख्य होस्ट को एक कमांड भेजता हूं और आउटपुट प्राप्त करता हूं:
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);
पोर्ट पर एक साधारण सर्वर पायथन सर्वर को सुनें (8080 कहते हैं), पोर्ट -p 8080: 8080 को कंटेनर से बांधें, लोकलहोस्ट के लिए एक HTTP अनुरोध करें: 8080 पॉपन के लिए शेल स्क्रिप्ट चलाने वाले अजगर सर्वर से पूछें, कर्ल चलाएं या एक HTTP अनुरोध कर्ल -d '{"foo": "बार"} लोकलहोस्ट: 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()
मेरे आलस्य ने मुझे सबसे आसान समाधान खोजने के लिए प्रेरित किया जो यहां एक उत्तर के रूप में प्रकाशित नहीं हुआ था।
यह पर आधारित है महान लेख द्वारा ल्यूक juggery ।
आपको अपने डॉक कंटेनर के भीतर से अपने लिनक्स होस्ट को एक पूर्ण शेल प्राप्त करने के लिए करने की आवश्यकता है:
docker run --privileged --pid=host -it alpine:3.8 \
nsenter -t 1 -m -u -n -i sh
स्पष्टीकरण:
- विशेषाधिकारित: कंटेनर को अतिरिक्त अनुमति देता है, यह कंटेनर को होस्ट (/ देव) के उपकरणों तक पहुंच प्राप्त करने की अनुमति देता है
--pid = host: कंटेनरों को डॉकर होस्ट (वीएम जिसमें डॉकर डेमन चल रहा है) की प्रक्रियाओं के पेड़ का उपयोग करने की अनुमति देता है। एनसेंटर उपयोगिता: मौजूदा नेमस्पेस (बिल्डिंग ब्लॉक्स जो कंटेनरों को अलगाव प्रदान करता है) में एक प्रक्रिया को चलाने की अनुमति देता है
nsenter (-t 1 -m -n -n -i sh) पीआईडी 1 के साथ प्रक्रिया के रूप में प्रक्रिया को उसी अलगाव संदर्भ में चलाने की अनुमति देता है। पूरे कमांड तब वीएम में एक इंटरैक्टिव श खोल प्रदान करेगा।
इस सेटअप के प्रमुख सुरक्षा निहितार्थ हैं और इसका उपयोग सावधानी (यदि कोई हो) के साथ किया जाना चाहिए।
docker run --detach-keys="ctrl-p" -it -v /:/mnt/rootdir --name testing busybox
# chroot /mnt/rootdir
#
मेरे पास एक सरल तरीका है।
चरण 1: Mount /var/run/docker.sock:/var/run/docker.sock (ताकि आप अपने कंटेनर के अंदर docker कमांड निष्पादित कर सकें)
चरण 2: अपने कंटेनर के अंदर इसे नीचे निष्पादित करें। यहाँ मुख्य भाग (- नेटवर्क होस्ट है क्योंकि यह होस्ट संदर्भ से निष्पादित होगा)
docker run -i --rm --network host -v /opt/test.sh:/test.sh अल्पाइन: 3.7 sh /test.sh
test.sh में कुछ कमांड्स होना चाहिए (ifconfig, netstat आदि ...) जो भी आपको चाहिए। अब आप मेजबान संदर्भ आउटपुट प्राप्त करने में सक्षम होंगे।
जैसा कि मार्कस याद दिलाते हैं, डॉक मूल रूप से अलगाव की प्रक्रिया है। Docker 1.8 से शुरू होकर, आप होस्ट और कंटेनर के बीच फ़ाइलों को कॉपी कर सकते हैं, डॉक्स को देख सकते हैंdocker cp
https://docs.docker.com/reference/commandline/cp/
एक बार किसी फ़ाइल की प्रतिलिपि बना लेने पर, आप इसे स्थानीय रूप से चला सकते हैं
myvalue=$(docker run -it ubuntu echo $PATH)और इसे स्क्रिप्ट शेल में नियमित रूप से परीक्षण करना (बेशक, आप $ PATH के अलावा कुछ और उपयोग करेंगे, बस एक उदाहरण है), जब यह कुछ विशिष्ट मूल्य है, आप अपनी स्क्रिप्ट
आप पाइप अवधारणा का उपयोग कर सकते हैं, लेकिन होस्ट पर एक फ़ाइल का उपयोग करें और डॉक कंटेनर से होस्ट मशीन पर स्क्रिप्ट निष्पादित करने के लिए लक्ष्य को पूरा करने के लिए fswatch । जैसे कि (अपने जोखिम पर उपयोग करें):
#! /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
इस उदाहरण में, कंटेनर के अंदर / dev / कमांड_पाइप करने के लिए कमांड भेजें, जैसे:
/home/test # echo 'docker network create test2.network.com' > /dev/command_pipe
होस्ट पर, आप जाँच सकते हैं कि क्या नेटवर्क बनाया गया था:
$ docker network ls | grep test2
8e029ec83afe test2.network.com bridge local
User2915097 की प्रतिक्रिया पर विस्तार करने के लिए :
अलगाव का विचार एक आवेदन / प्रक्रिया / कंटेनर (जो भी इस पर आपका कोण है) को प्रतिबंधित करने में सक्षम होना चाहिए जो मेजबान प्रणाली को बहुत स्पष्ट रूप से कर सकता है। इसलिए, किसी फ़ाइल को कॉपी और निष्पादित करने में सक्षम होना वास्तव में पूरी अवधारणा को तोड़ देगा।
हाँ। लेकिन यह कभी-कभी जरूरी होता है।
नहीं, यह मामला नहीं है, या डॉकर उपयोग करने के लिए सही बात नहीं है। आपको जो करना चाहिए, उसके लिए एक स्पष्ट इंटरफ़ेस घोषित करना चाहिए (जैसे होस्ट कॉन्फ़िगरेशन को अपडेट करना), और वास्तव में ऐसा करने के लिए एक न्यूनतम क्लाइंट / सर्वर लिखें और इससे ज्यादा कुछ नहीं। आम तौर पर, हालांकि, यह बहुत वांछनीय नहीं लगता है। कई मामलों में, आपको बस अपने दृष्टिकोण पर पुनर्विचार करना चाहिए और उस आवश्यकता को मिटाना चाहिए। डॉकर एक अस्तित्व में आया जब मूल रूप से सब कुछ एक सेवा थी जो कुछ प्रोटोकॉल का उपयोग करके उपलब्ध थी। मैं डॉकटर कंटेनर के किसी भी उचित उपयोग के बारे में नहीं सोच सकता, जिसे मेजबान पर मनमाना सामान निष्पादित करने का अधिकार प्राप्त हो।
A( sith on github) की है। में Aरेपो मैं उचित हुक जो 'Git पुल' आदेश के बाद नई डोकर छवि बनाने और उन्हें चलाने (और निश्चित रूप से पुराने कंटेनर निकालने के लिए) पैदा करते हैं। अगला: github में वेब-हुक हैं जो मास्टर पर पुश करने के बाद मनमाने समापन बिंदु लिंक के लिए POST अनुरोध बनाने की अनुमति देते हैं। इसलिए मैं डॉक्यूमेंटेड सर्विस B नहीं बनाना चाहता, जो कि एंडपॉइंट होगा और जो केवल HOST मशीन में रेपो ए में 'git पुल' चलाएगा (महत्वपूर्ण: कमांड 'git पुल' को HOST वातावरण में निष्पादित किया जाना चाहिए - B में नहीं क्योंकि B नए कंटेनर A को B के अंदर नहीं चला सकते ...)