LXCホストとして機能するUbuntu14.04サーバーをインストールしています。 user1とuser2の2人のユーザーがいます。
user1は非特権のLXCコンテナーを所有しており、バッキングストアとしてディレクトリ(/home/user1/.local/...内)を使用します。
User2のコンテナの完全なコピーを作成するにはどうすればよいですか?ユーザー1にバインドされている100000から100000+何かの範囲の所有者にマップされているため、ファイルをコピーすることはできません。
また、基本的に同じ質問だと思いますが、user1のLXCコンテナーのバックアップを安全に作成して、後で別のマシンやユーザーに復元するにはどうすればよいですか?
fuidshift
はこの目的のために作成されました。 LXDの一部のようです。
http://manpages.ubuntu.com/manpages/xenial/man1/fuidshift.1.html
私は今これを行う方法を知っています。この説明に従えない場合は、質問してください。また、下部にある読み物でユーザーについて読んだことを確認してください。
私はあなたの質問から私が持っているものから拡張された次の仮定に固執します:
user1
_と_user2
_があります。情報が特定されていない場合は、userX
を使用します。$container
_としてレンダリングする変数によって名前が付けられます。user1
_および_user2
_のホームフォルダーは、Bashで_~user1
_および_~user2
_と呼ばれる表記で指定されます。user1
_の場合は100000..165536、_user2
_の場合は200000..265536であると想定します。$container
_のルートFSフォルダーは、最終的にどこにあるかに関係なく、_$rootfs
_としてレンダリングされます(_~userX/.local/share/lxc/$container/rootfs
_)~userX/.local/share/lxc/$container/config
_にありますuserns
コンテナを管理する2つの関連データがあります。
$container
_を構成するフォルダーのファイル/フォルダーの所有者とグループ/etc/sub{uid,gid}
_(_usermod --{add,del}-sub-{uid,gid}s
_を介して操作)と_lxc.id_map
_構成(_$container
_)の_~userX/.local/share/lxc/$container/config
_ userX
に65536の従属GIDとUIDがある場合、5000から65の異なるコンテナーを割り当てることができる可能性がありますが、その仮説はテストしていません。したがって、要点は、コンテナのファイル/フォルダの所有者とグループが構成と一致していることを確認する必要があるということです。構成は、_user1
_とに割り当てられたホストの従属GID/UIDの有効なサブセットである必要があります。それぞれ_user2
_。
たとえば、Bashを使用している場合は、算術式に$((expression))
を使用し、変数に算術式を割り当てるためにlet
を使用できます。これは、基本値(それぞれ100000と200000)と「内部」ユーザーのGID/UIDがわかっている場合に非常に役立ちます。
主なポイントは次のとおりです。
CAP_CHOWN
_ またはスーパーユーザー権限が必要ですこれはおそらくもう少し研ぎ澄まされる必要があるスクリプトです(例:ルートで作成されたコンテナーから非特権への移行)が、それは目的のために私のために働きます:
_#!/usr/bin/env bash
function syntax
{
echo "SYNTAX: ${0##*/} <from-user> <to-user> <container-name>"
[[ -n "$1" ]] && echo -e "\nERROR: ${1}."
exit 1
}
# Checks
[[ -n "$1" ]] || syntax "<from-user> is not set"
[[ -n "$2" ]] || syntax "<to-user> is not set"
[[ -n "$3" ]] || syntax "<container-name> is not set"
[[ "$UID" -eq "0" ]] || syntax "${0##*/}" "You must be superuser to make use of this script"
# Constants with stuff we need
readonly USERFROM=$1
readonly USERTO=$2
shift; shift
readonly CONTAINER=${1:-*}
LXCLOCAL=".local/share/lxc"
readonly HOMEFROM=$(eval echo ~$USERFROM)
readonly HOMETO=$(eval echo ~$USERTO)
readonly LXCFROM="$HOMEFROM/$LXCLOCAL"
readonly LXCTO="$HOMETO/$LXCLOCAL"
readonly GIDBASEFROM=$(awk -F : "\$1 ~/$USERFROM/ {print \$2}" /etc/subgid)
readonly UIDBASEFROM=$(awk -F : "\$1 ~/$USERFROM/ {print \$2}" /etc/subuid)
readonly GIDSIZEFROM=$(awk -F : "\$1 ~/$USERFROM/ {print \$3}" /etc/subgid)
readonly UIDSIZEFROM=$(awk -F : "\$1 ~/$USERFROM/ {print \$3}" /etc/subuid)
readonly GIDBASETO=$(awk -F : "\$1 ~/$USERTO/ {print \$2}" /etc/subgid)
readonly UIDBASETO=$(awk -F : "\$1 ~/$USERTO/ {print \$2}" /etc/subuid)
readonly GIDSIZETO=$(awk -F : "\$1 ~/$USERTO/ {print \$3}" /etc/subgid)
readonly UIDSIZETO=$(awk -F : "\$1 ~/$USERTO/ {print \$3}" /etc/subuid)
unset LXCLOCAL
# More checks
[[ -d "$LXCFROM" ]] || syntax "Could not locate '$LXCFROM'. It is not a directory as expected"
[[ -e "$LXCTO" ]] && syntax "Destination '$LXCTO' already exists. However, it must not"
for i in GIDBASEFROM UIDBASEFROM GIDBASETO UIDBASETO; do
(($i > 0)) || syntax "Could not determine base/offset of subordinate UID/GID range"
done
for i in GIDSIZEFROM UIDSIZEFROM GIDSIZETO UIDSIZETO; do
(($i > 0)) || syntax "Could not determine length of subordinate UID/GID range"
done
echo "Going to migrate container: $CONTAINER"
echo -e "\tfrom user $USERFROM ($HOMEFROM): subUID=${UIDBASEFROM}..$((UIDBASEFROM+UIDSIZEFROM)); subGID=${GIDBASEFROM}..$((GIDBASEFROM+GIDSIZEFROM))"
echo -e "\tto user $USERTO ($HOMETO): subUID=${UIDBASETO}..$((UIDBASETO+UIDSIZETO)); subGID=${GIDBASETO}..$((GIDBASETO+GIDSIZETO))"
while read -p "Do you want to continue? (y/N) "; do
case ${REPLY:0:1} in
y|Y)
break;
;;
*)
echo "User asked to abort."
exit 1
;;
esac
done
# Find the UIDs and GIDs in use in the container
readonly SUBGIDSFROM=$(find -H "$LXCFROM" -printf '%G\n'|sort -u)
readonly SUBUIDSFROM=$(find -H "$LXCFROM" -printf '%U\n'|sort -u)
# Change group
for gid in $SUBGIDSFROM; do
let GIDTO=$(id -g "$USERTO")
if ((gid == $(id -g "$USERFROM"))); then
echo "Changing group from $USERFROM ($gid) to $USERTO ($GIDTO)"
find -H "$LXCFROM/$CONTAINER" -gid $gid -exec chgrp $GIDTO {} +
Elif ((gid >= GIDBASEFROM )) && ((gid <= GIDBASEFROM+GIDSIZEFROM)); then
let GIDTO=$((gid-GIDBASEFROM+GIDBASETO))
echo "Changing group $gid -> $GIDTO"
find -H "$LXCFROM/$CONTAINER" -gid $gid -exec chgrp $GIDTO {} +
else
echo "ERROR: Some file/folder inside '$LXCFROM/$CONTAINER' has a group not assigned to $USERFROM (assigned subordinate GIDs)."
echo -e "Use:\n\tfind -H '$LXCFROM/$CONTAINER' -gid $gid\nto list those files/folders."
exit 1
fi
done
# Change owner
for uid in $SUBUIDSFROM; do
let UIDTO=$(id -u "$USERTO")
if ((uid == $(id -u "$USERFROM"))); then
echo "Changing owner from $USERFROM ($uid) to $USERTO ($UIDTO)"
find -H "$LXCFROM/$CONTAINER" -uid $uid -exec chown $UIDTO {} +
Elif ((uid >= UIDBASEFROM )) && ((uid <= UIDBASEFROM+UIDSIZEFROM)); then
let UIDTO=$((uid-UIDBASEFROM+UIDBASETO))
echo "Changing owner $uid -> $UIDTO"
find -H "$LXCFROM/$CONTAINER" -uid $uid -exec chown $UIDTO {} +
else
echo "ERROR: Some file/folder inside '$LXCFROM/$CONTAINER' has an owner not assigned to $USERFROM (assigned subordinate UIDs)."
echo -e "Use:\n\tfind -H '$LXCFROM/$CONTAINER' -uid $uid\nto list those files/folders."
exit 1
fi
done
mv "$LXCFROM/$CONTAINER" "$LXCTO/" || { echo "ERROR: failed to move to destination: ${LXCTO}/${CONTAINER}."; exit 1; }
_
StackExchangeネットワークのライセンス条項に加えて、私はこれをパブリックドメインに入れています。したがって、目的を問わず再利用および変更しますが、保証はなく、その使用または乱用について私は責任を負わないものとします。
_SYNTAX: lxc-reassign-userns.sh <from-user> <to-user> <container-name>
_
find
、sort
、uniq
、awk
(mawk
およびgawk
が機能するはずです)、id
、bash
、chown
、chmod
などを使用できるようにし、使用しているすべてのコマンドラインスイッチを理解します。 Bashの場合、readonly
およびlet
と算術式は、理解されていると見なされます。 find
の場合、_+
_が_-exec
_アクションの有効なターミネータであると想定されます。
このリストはおそらく完全ではありません。
はい。ファイルの所有者とグループを適宜調整する限り、バックアップを作成して他の場所に復元できます。
ただし、tar
のようなものを使用すると仮定すると、警告があります。tar
はソケットを無視するため、_$rootfs/dev/log
_が問題を引き起こします。他の人も同様の問題を引き起こす可能性があります。
LXCコンテナを含むディレクトリをuser1からuser2にコピーし、次のpythonコードを使用してUIDとGIDをシフトすることができます:
#!/usr/bin/python3
import os
import sys
uidmap_start = 100000
uidmap_size = 65536
gidmap_start = 100000
gidmap_size = 65536
def changeUidGidRecursive(path):
changeUidGid(path)
if os.path.isdir(path) and not os.path.islink(path):
for filename in os.listdir(path):
sub_path = os.path.join(path, filename)
changeUidGidRecursive(sub_path)
def changeUidGid(path):
stat_info = os.lstat(path)
uid = stat_info.st_uid
gid = stat_info.st_gid
new_uid = uid + uidmap_start
new_gid = gid + gidmap_start
if (new_uid > uidmap_end):
print("Info: New UID %d for \"%s\" would be out of range. Not changing UID." % (new_uid, path))
new_uid = uid
if (new_gid > gidmap_end):
print("Info: New GID %d for \"%s\" would be out of range. Not changing GID." % (new_gid, path))
new_gid = gid
if (new_uid != uid or new_gid != gid):
mode = stat_info.st_mode
os.chown(path, new_uid, new_gid, follow_symlinks=False)
new_mode = os.lstat(path).st_mode
# If necessary, restore old mode
if (new_mode != mode):
os.chmod(path, mode)
if __name__ == '__main__':
uidmap_end = uidmap_start + uidmap_size
gidmap_end = gidmap_start + gidmap_size
base_path = ''
if len(sys.argv) > 1:
base_path = sys.argv[1]
else:
print("Usage: %s <path>" % (sys.argv[0]))
sys.exit(1)
if not os.path.exists(base_path):
print("Error: Path \"%s\" does not exist" % (base_path))
print("Exiting")
sys.exit(1)
changeUidGidRecursive(base_path)
sys.exit(0)
uidmap_start
、gidmap_size
、場合によってはuidmap_size
とgidmap_size
をニーズに合わせて調整する必要があります。
このpythonコードを使用して、特権LXCコンテナーを非特権コンテナーに移行しました。pythonコードは、シェルスクリプトよりも高速に実行されます。