Dockerコンテナからホストへのファイルのコピー方法📋
24580 ワード
最近、Dockerコンテナからファイルをダウンロードする必要がありました.ファイルが内部でなかったのでbind mount , ファイルシステム上のファイルを取得するには、リモートサーバーに直接アクセスできませんでした.
それで、我々は速く見つかりましたdocker cp ユーティリティは、我々のホストとvoilaの上でファイルをコピーするために、我々は我々のコンピュータにファイルを持っていました.☺️
残念ながら、コンテナの正確な名前を知りませんでした
そして、我々は我々のスタックを配備したのでswarm mode , 我々は、使用できませんでしたcontainer_name option このモードでは無視されます.
そこで、コンテナのフルネームを取得するにはdocker ps コマンドを実行します.
これらのコマンドを組み合わせると、私たちのファイルをダウンロードするのに1つのコマンドしか使えません.
それは私たちのローカルコンピュータ上でうまく動作しましたが、私たちが興味を持っていた本当のファイルはリモートサーバーにありました.そして、それはすべてが我々のために複雑になるところです.🤮
制約 我々は、我々がちょうど若干の情報を提供することができた自動解決を望みました、そして、我々はファイルを得ます.🤖 コンテナはDockerマシンのプールからランダムサーバー上でホストされました.🌈 私たちは特定のDockerコマンドを実行する特権ユーザーでなければなりませんでした.👑 多くの推測と誤りの後、我々は最終的にこれらの制約の下で解決策を得ることができました、しかし、それは予想されるより長くかかりました.我々が遭遇した問題のいくつかに飛び込みましょう.😌
課題
リモートサーバーでsudoコマンドを走らせる方法
私の意見では、このステップは、我々の最終的なスクリプトの最も複雑な部分です.以下のようなことを説明してください.🤢
SSH経由で複数のコマンドを実行するには、here document リモートホスト上で実行するすべてのコマンドを一覧表示する構造体. 変数はこの構造体の内部で置き換えられなかったので、envsubst コマンド. シェル変数を コンテナ名を変数に捕捉したかったので、1行コマンドがうまく動かなかったので、コマンドを分割しました 私のユーザはこのサーバでDockerコマンドを実行できなかったので、root権限を得なければなりませんでした.我々は多くの(多くの)試みを試みました、そして、我々は最初に我々のパスワードを出力することによって、解決策を得ることができました まだ私に知られていない理由のために
リモートサーバーからホストへファイルを移す方法
この部分は見つけるのが簡単だったsshpass and scp コマンド.
以前はサーバーにSSH公開鍵をインストールしていたので、ホスト名とサーバー上で同じユーザ名を使用しているので、次のように前のコマンドを書き換えることができます.
簡単、右?😉
アプリケーションコンテナが動くサーバーを見つける方法
サーバーのクラスタを参照するには、単純なスイッチケースとともに、配列としてリストを提供しています.BASHのスイッチケースの例が必要な場合は常に便利です.😋
残念ながら、どのサーバにファイルを転送する必要があるのかを知ることができないので、それぞれのサーバ上のすべてのコマンドを実行しなければなりません.😵💫
だから、我々は多くを得る
引数の確保方法
いくつかの引数が供給されないか、正しくないならば、我々のスクリプトが失敗することができたので、我々はこれらのケースを確かめるために若干の状況を加えました.
最終解決
一緒にすべての作品を一緒に置く場合、我々の最終的なスクリプトは以下のようになります.🧩
このポストがあなたに役に立つという望み!安全!🍻
それで、我々は速く見つかりましたdocker cp ユーティリティは、我々のホストとvoilaの上でファイルをコピーするために、我々は我々のコンピュータにファイルを持っていました.☺️
docker cp CONTAINER_NAME:/opt/service/FILENAME_TO_OBTAIN .
単純な例docker cp
コンテナの名前が既知のコマンドです.残念ながら、コンテナの正確な名前を知りませんでした
docker compose
デフォルトでは、ランダムに生成された16進文字列、例えば.eq6l28g5mwsenh0gvag7zcg0j
. 😶🌫️そして、我々は我々のスタックを配備したのでswarm mode , 我々は、使用できませんでしたcontainer_name option このモードでは無視されます.
そこで、コンテナのフルネームを取得するにはdocker ps コマンドを実行します.
--format
オプションは、そのフルネームを取得します.docker ps --format='{{.Names}}' | grep "CONTAINER_NAME_PREFIX"
の例docker ps
コンテナ名の接頭辞を知っているコマンド.これらのコマンドを組み合わせると、私たちのファイルをダウンロードするのに1つのコマンドしか使えません.
docker cp "$(docker ps --format='{{.Names}}' | grep "CONTAINER_NAME_PREFIX")":"/opt/service/FILENAME_TO_OBTAIN" .
結果として、コンテナからファイルをホストにコピーできます.それは私たちのローカルコンピュータ上でうまく動作しましたが、私たちが興味を持っていた本当のファイルはリモートサーバーにありました.そして、それはすべてが我々のために複雑になるところです.🤮
制約
課題
リモートサーバーでsudoコマンドを走らせる方法
私の意見では、このステップは、我々の最終的なスクリプトの最も複雑な部分です.以下のようなことを説明してください.🤢
# Define and export some variables that will be used in this part
export SERVER=SERVER_HOSTNAME
export FILENAME=FILENAME_TO_OBTAIN
export CONTAINER_PREFIX=ranb2002_system
export PASSWORD=PASSWORD_TO_BE_ROOT
# Create a template where the environment variables will be replaced
TEMPLATE=$(
envsubst <<'EOF'
# Authenticate as sudo and pass the password without indentation
sudo -S whoami
$PASSWORD
# Delete the previous file if it exists on the server
rm -f "${FILENAME}"
# List all Docker containers on this server
CONTAINERS=$(sudo -S docker ps --format='{{.Names}}')
# Check if we have a container for our application on this server
CONTAINER_NAME=$(printf '%s\n' "${CONTAINERS[@]}" | grep "${CONTAINER_PREFIX}")
# Otherwise, continue to the next server
if [-z "${CONTAINER_NAME[0]}" ]; then
echo "The container with name ${CONTAINER_PREFIX} was not found on this server ($(hostname))... :("
exit
fi
echo "The container with name ${CONTAINER_NAME[0]} was found on this server ($(hostname))! :)"
# Copy the file from the container to the current host
sudo -S docker cp "${CONTAINER_NAME[0]}":"/opt/service/${FILENAME}" .
EOF
)
# Connect to the server and run all commands from the template
ssh -T "${USER}@${SERVER}" <<< "$TEMPLATE"
スクリプトはリモートサーバに多数のコマンドを実行します.envsubst
, 私たちはexport
それら.sudo
. sudo -S
コマンド.以下のコマンドはパスワードを再び必要としません.🥺 CONTAINER_NAME
変数は配列です.だから、それにアクセスするには、我々は選択するしかなかったCONTAINER_NAME[0]
... 🤷 As you may have noticed, we didn't need to pass our password when running the
ssh
command, because we are using SSH public keys. If you want to install SSH keys on your servers, check out my article on how to automate ssh-copy-id! 😉
リモートサーバーからホストへファイルを移す方法
この部分は見つけるのが簡単だったsshpass and scp コマンド.
# Copy the file from the remote server to our host
sshpass -p "${PASSWORD}" scp "${USER}@${SERVER}":"/home/${USER}/${FILENAME}" .
使用sshpass
リモートサーバーへの接続時にパスワードプロンプトを抑制します.以前はサーバーにSSH公開鍵をインストールしていたので、ホスト名とサーバー上で同じユーザ名を使用しているので、次のように前のコマンドを書き換えることができます.
scp "${SERVER}":"~/${FILENAME}" .
いくつかの仮定を行うことができます小さなコマンド.簡単、右?😉
アプリケーションコンテナが動くサーバーを見つける方法
サーバーのクラスタを参照するには、単純なスイッチケースとともに、配列としてリストを提供しています.BASHのスイッチケースの例が必要な場合は常に便利です.😋
case "${ENVIRONMENT}" in
DEV)
SERVERS=(
"DEV_SERVER_1_HOSTNAME"
"DEV_SERVER_2_HOSTNAME"
)
;;
TEST)
SERVERS=(
"TEST_SERVER_1_HOSTNAME"
"TEST_SERVER_2_HOSTNAME"
)
;;
*)
SERVERS=(
"PRODUCTION_SERVER_1_HOSTNAME"
"PRODUCTION_SERVER_2_HOSTNAME"
)
;;
esac
for SERVER in "${SERVERS[@]}"; do
# All previous commands
done
forループに必要なサーバを一覧表示するスイッチケース.残念ながら、どのサーバにファイルを転送する必要があるのかを知ることができないので、それぞれのサーバ上のすべてのコマンドを実行しなければなりません.😵💫
だから、我々は多くを得る
scp: /home/ranb2002/[...]: No such file or directory
1つのサーバだけが必要なファイルを持っているのでエラーが発生します.😒引数の確保方法
いくつかの引数が供給されないか、正しくないならば、我々のスクリプトが失敗することができたので、我々はこれらのケースを確かめるために若干の状況を加えました.
Note : if the password is incorrect or if the user is not a privileged user, the script will still fail because we haven't taken some time to figure out how to prevent this.
#!/bin/bash
echo "Usage:"
echo " ./scripts/copy_config.sh 'PASSWORD' ENVIRONMENT"
echo " where ENVIRONMENT is DEV, TEST, DEMO or PROD."
echo ""
# Make sure we have your password
if [-z "${1}"]; then
echo "You must provide your password!"
exit
fi
# Export the password to an environment variable
export PASSWORD="${1}"
# Make sure we have the environment
if [-z "${2}"]; then
echo "You must provide the environment!"
exit
fi
export ENVIRONMENT="${2}"
# Make sure the environment provided is supported
ENVIRONMENTS=("DEV" "TEST" "DEMO" "PROD")
if [[! " ${ENVIRONMENTS[*]} " == *" ${ENVIRONMENT} "* ]]; then
#
echo "The environment provided is incorrect!"
exit
fi
スクリプトの開始時にチェックしたものもあります.Bonus : if for some reason you need to transform an uppercase value to its lowercase equivalent, here is the Bash command you can use:
LOWER_ENVIRONMENT=$(echo "${ENVIRONMENT}" | awk '{print tolower($0)}')
. 😜
最終解決
一緒にすべての作品を一緒に置く場合、我々の最終的なスクリプトは以下のようになります.🧩
#!/bin/bash
echo "Usage:"
echo " ./scripts/copy_config.sh 'PASSWORD' ENVIRONMENT"
echo " where ENVIRONMENT is DEV, TEST, DEMO or PROD."
echo ""
# Make sure we have your password
if [-z "${1}"]; then
echo "You must provide your password!"
exit
fi
# Export the password to an environment variable
export PASSWORD="${1}"
# Make sure we have the environment
if [-z "${2}"]; then
echo "You must provide the environment!"
exit
fi
export ENVIRONMENT="${2}"
# Make sure the environment provided is supported
ENVIRONMENTS=("DEV" "TEST" "DEMO" "PROD")
if [[! " ${ENVIRONMENTS[*]} " == *" ${ENVIRONMENT} "* ]]; then
#
echo "The environment provided is incorrect!"
exit
fi
LOWER_ENVIRONMENT=$(echo "${ENVIRONMENT}" | awk '{print tolower($0)}')
export DOCKER_STACK="stack-${LOWER_ENVIRONMENT}_service"
export FILENAME="FILENAME_TO_DOWNLOAD"
case "${ENVIRONMENT}" in
DEV)
SERVERS=(
"DEV_SERVER_1_HOSTNAME"
"DEV_SERVER_2_HOSTNAME"
)
;;
TEST)
SERVERS=(
"TEST_SERVER_1_HOSTNAME"
"TEST_SERVER_2_HOSTNAME"
)
;;
*)
SERVERS=(
"PRODUCTION_SERVER_1_HOSTNAME"
"PRODUCTION_SERVER_2_HOSTNAME"
)
;;
esac
for SERVER in "${SERVERS[@]}"; do
TEMPLATE=$(
envsubst <<'EOF'
# Authenticate as sudo and pass the password with no indentation
sudo -S whoami
$PASSWORD
# Delete the previous file if it exists
rm -f "${FILENAME}"
# List all Docker containers on this server
CONTAINERS=$(sudo -S docker ps --format='{{.Names}}')
# Check if we have a container for our application on this server
CONTAINER_NAME=$(printf '%s\n' "${CONTAINERS[@]}" | grep "${DOCKER_STACK}")
# Otherwise, continue to the next server
if [-z "${CONTAINER_NAME[0]}" ]
then
echo "The container with name ${DOCKER_STACK} was not found on this server ($(hostname))... :("
exit
fi
echo "The container with name ${CONTAINER_NAME[0]} was found on this server ($(hostname))! :)"
# Copy the file from the container to the current host
sudo -S docker cp "${CONTAINER_NAME[0]}":"/opt/service/${FILENAME}" .
EOF
)
# Connect to the server and run all commands from the template
ssh -T "${SERVER}" <<< "$TEMPLATE"
# Copy the file from the server to our computer
# shellcheck disable=SC2140
scp "${SERVER}":"~/${FILENAME}" .
done
ちょうどDockerコンテナからファイルをダウンロードする複雑なスクリプト、右?このポストがあなたに役に立つという望み!安全!🍻
Reference
この問題について(Dockerコンテナからホストへのファイルのコピー方法📋), 我々は、より多くの情報をここで見つけました https://dev.to/benjaminrancourt/how-to-copy-a-file-from-a-docker-container-to-the-host-2hi5テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol