Tôi biết bây giờ làm thế nào để làm điều này. Nếu bạn không thể làm theo lời giải thích này, vui lòng hỏi lại, nhưng cũng đảm bảo rằng bạn đã đọc được những điều hữu ích trong các bài đọc tôi đang đưa ra ở phía dưới
Giả định sơ bộ
Tôi sẽ kiên định với các giả định sau, mở rộng từ những gì tôi có từ câu hỏi của bạn:
- máy chủ lưu trữ có một
user1
và user2
, nếu một thông tin không cụ thể cho một người, chúng tôi sẽ sử dụnguserX
- container sẽ được đặt tên theo một biến mà chúng ta sẽ kết xuất là
$container
- thư mục nhà cho
user1
và user2
sẽ được đưa ra trong ký hiệu được biết đến từ Bash như ~user1
và ~user2
.
- chúng tôi sẽ giả sử phạm vi UID và GID cấp dưới là 100000..165536 cho
user1
và 200000..265536 user2
chỉ để đơn giản
- thư mục FS gốc
$container
sẽ được hiển thị dưới dạng $rootfs
, bất kể nơi nào nó sẽ kết thúc ( ~userX/.local/share/lxc/$container/rootfs
)
- cấu hình container theo mặc định trong
~userX/.local/share/lxc/$container/config
Di chuyển container
Có hai phần dữ liệu liên quan chi phối các userns
container:
- chủ sở hữu và nhóm cho các tệp / thư mục của các thư mục chứa
$container
- các UID và GID cấp dưới được gán ở hai vị trí:
/etc/sub{uid,gid}
cho tài khoản người dùng (được thao tác thông qua usermod --{add,del}-sub-{uid,gid}s
) và lxc.id_map
trong $container
cấu hình ( ~userX/.local/share/lxc/$container/config
) tương ứng
- Tôi không biết chắc chắn liệu có thể xác định các phạm vi khác nhau trong cấu hình vùng chứa cho mỗi vùng chứa hay không. Ví dụ: nếu người dùng máy chủ
userX
có 65536 GID và UID cấp dưới, có thể chỉ định 5000 đến 65 container khác nhau, nhưng tôi chưa kiểm tra giả thuyết đó.
- tuy nhiên, chắc chắn rằng cài đặt này giao tiếp với LXC là các phạm vi hợp lệ cho GID và UID trong không gian tên con.
Vì vậy, ý chính thực sự là bạn cần đảm bảo rằng chủ sở hữu tệp và thư mục cho vùng chứa khớp với cấu hình, đến lượt nó phải là một tập hợp con hợp lệ của các GID / UID cấp dưới được gán cho user1
và user2
tương ứng.
Ví dụ: nếu bạn đang sử dụng Bash, bạn có thể sử dụng $((expression))
cho các biểu thức số học và let
để gán các biểu thức số học cho các biến. Điều này rất hữu ích nếu bạn biết giá trị cơ bản (tương ứng 100000 và 200000) và GID / UID cho người dùng "bên trong".
Những điểm chính là:
- nó có thể
- hoặc khả năng
CAP_CHOWN
hoặc quyền siêu người dùng được yêu cầu
Đây là một tập lệnh có thể sẽ cần thêm một số mài giũa (ví dụ: di chuyển từ bộ chứa được tạo gốc sang không có đặc quyền), nhưng nó hoạt động với mục đích của tôi:
#!/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; }
Ngoài các điều khoản cấp phép của mạng StackExchange, tôi sẽ đưa điều này vào phạm vi công cộng. Vì vậy, tái sử dụng và sửa đổi cho bất kỳ mục đích nào, nhưng nó không có bất kỳ sự bảo đảm nào và tôi không phải chịu trách nhiệm cho việc sử dụng hoặc lạm dụng nó.
Sử dụng
SYNTAX: lxc-reassign-userns.sh <from-user> <to-user> <container-name>
Nó giả định find
, sort
, uniq
, awk
( mawk
và gawk
nên làm việc), id
, bash
, chown
, chmod
và vân vân có sẵn và để hiểu tất cả các dòng lệnh chuyển nó đang sử dụng. Đối với Bash readonly
và các let
biểu thức số học được giả sử là được hiểu. Cho find
là giả định +
là một kết thúc hợp lệ cho -exec
hành động.
Danh sách này có lẽ không đầy đủ.
Sao lưu
Có, bạn có thể tạo bản sao lưu và khôi phục chúng ở nơi khác, miễn là bạn cũng điều chỉnh chủ sở hữu tệp và nhóm cho phù hợp.
Tuy nhiên, giả sử bạn sử dụng một cái gì đó như tar
, có một cảnh báo: tar
sẽ bỏ qua các ổ cắm, do đó $rootfs/dev/log
sẽ gây ra vấn đề - những người khác cũng có thể tạo ra một vấn đề tương tự.
Tài nguyên:
cp
thay vìmv
với các cờ thích hợp để giữ tất cả các thuộc tính bạn cần giữ trong tập lệnh của tôi.