stateless linux是fedoracore的一个项目,顾名思义,就是系统运行时不保存持久状态信息,简单来说就是不让系统对持久存储设备(比如硬盘)进行写操作。一般用于readonly root技术。在我最近的程序中,用stateless linux来达到多个虚拟机共享同一份磁盘image。
stateless linux的设置文件是/etc/sysconfig/readonly-root,/etc/rc.sysinit在系统启动时读取这个文件,并根据文件中的设置进行配置。
从/etc/rc.sysinit中摘取出来的关于readonly-root的设置代码,在代码中添加了注释:
READONLY=
if [ -f /etc/sysconfig/readonly-root ]; then
. /etc/sysconfig/readonly-root
fi
#/etc/sysconfig/readonly-root设置READONLY,TEMPORARY_STATE,RW_MOUNT,RW_LABEL,STATE_LABEL,STATE_MOUNT几个变量。
#在readonly-root文件中对这几个变量的作用做了详细的注释。从下面的代码中也可以体现出来。
if strstr "$cmdline" readonlyroot ; then
READONLY=yes
[ -z "$RW_MOUNT" ] && RW_MOUNT=/var/lib/stateless/writable
fi
#cmdline变量就是启动时传递给kernel的参数,可以从/proc/cmdline中看到,例如:ro root=LABEL=/
if strstr "$cmdline" noreadonlyroot ; then
READONLY=no
fi
# READONLY和TEMPORARY_STATE只要设置其中一个为yes就可以。
if [ "$READONLY" = "yes" -o "$TEMPORARY_STATE" = "yes" ]; then
#mount_empty函数的作用就是把参数$1指定的文件或目录复制到$RW_MOUNT目录下作为备份,然后把备份文件使用bind方式mount到原来的文件上。
#这样原来的文件仍然可见可读,而且保证了只读,因为所有的写操作都会作用在备份文件上。cpio的-p参数指定了目标文件夹是$RW_MOUNT,-d参数
#表示如果$1是多级目录表示的一个文件,则这个目录结构会自动在$RW_MOUNT下原样创建。如果$1是一个目录,则目录下的文件不会被复制,这应该
#是mount_empty中的empty的意思。
mount_empty() {
if [ -e "$1" ]; then
echo "$1" | cpio -p -vd "$RW_MOUNT" &>/dev/null
mount -n --bind "$RW_MOUNT$1" "$1"
fi
}
#如果$1是一个目录,则mount_dirs把$1下层的目录结构按照原样在$RW_MOUNT下创建。
mount_dirs() {
if [ -e "$1" ]; then
mkdir -p "$RW_MOUNT$1"
# fixme: find is bad
find "$1" -type d -print0 | cpio -p -0vd "$RW_MOUNT" &>/dev/null
mount -n --bind "$RW_MOUNT$1" "$1"
fi
}
mount_files() {
if [ -e "$1" ]; then
cp -a --parents "$1" "$RW_MOUNT"
mount -n --bind "$RW_MOUNT$1" "$1"
fi
}
#简而言之,mount_{empty,dirs,files}都是针对参数$1而言,mount_empty只管$1,不管$1下面的任何结点,mount_dirs只管维持$1下层的目录结构,
#mount_files维持$1下面的所有目录和文件。
# Common mount options for scratch space regardless of
# type of backing store
mountopts=
#blkid命令用来索引或查看block设备的属性。-t参数用来指定一个属性(属性以name=value的方式表示,例如LABEL=/),-l参数表示
#搜索其属性值和-t参数指定的属性值符合的block设备。-o指定输出格式,可选的有full, value, device。以下是输出示例。
#[root@jcwkyl etc]# blkid -t LABEL=/ -l -o full
#/dev/sda3: LABEL="/" UUID="8844f9c3-2836-4f29-aaab-3fb6b6d0a1bf" SEC_TYPE="ext2" TYPE="ext3"
#[root@jcwkyl etc]# blkid -t LABEL=/ -l -o value
#/
#8844f9c3-2836-4f29-aaab-3fb6b6d0a1bf
#ext2
#ext3
#[root@jcwkyl etc]# blkid -t LABEL=/ -l -o device
#/dev/sda3
# Scan partitions for local scratch storage
rw_mount_dev=$(blkid -t LABEL="$RW_LABEL" -l -o device)
#这段代码中的注释说的非常清楚了,首先尝试从/etc/fstab中的设置来mount,如果/etc/fstab中没有设置,
#则直接把上一步找到的分区mount到$RW_MOUNT,如果还没有成功,则把$RW_MOUNT目录mount成tmpfs
# First try to mount scratch storage from /etc/fstab, then any
# partition with the proper label. If either succeeds, be sure
# to wipe the scratch storage clean. If both fail, then mount
# scratch storage via tmpfs.
if mount $mountopts "$RW_MOUNT" > /dev/null 2>&1 ; then
rm -rf "$RW_MOUNT" > /dev/null 2>&1
elif [ x$rw_mount_dev != x ] && mount $rw_mount_dev $mountopts"$RW_MOUNT" > /dev/null 2>&1; then
rm -rf "$RW_MOUNT" > /dev/null 2>&1
else
mount -n -t tmpfs $mountopts none "$RW_MOUNT"
fi
for file in /etc/rwtab /etc/rwtab.d/* ; do
is_ignored_file "$file" && continue
[ -f $file ] && cat $file | while read type path ; do
case "$type" in
empty)
mount_empty $path
;;
files)
mount_files $path
;;
dirs)
mount_dirs $path
;;
*)
;;
esac
[ -n "$SELINUX_STATE" -a -e "$path" ] && restorecon -R "$path"
done
done
# In theory there should be no more than one network interface active
# this early in the boot process -- the one we're booting from.
# Use the network address to set the hostname of the client. This
# must be done even if we have local storage.
ipaddr=
if [ "$HOSTNAME" = "localhost" -o "$HOSTNAME" = "localhost.localdomain" ]; then
ipaddr=$(ip addr show to 0/0 scope global | awk'/[[:space:]]inet / { print gensub("/.*","","g",$2) }')
if [ -n "$ipaddr" ]; then
eval $(ipcalc -h $ipaddr 2>/dev/null)
hostname ${HOSTNAME}
fi
fi
# Clients with read-only root filesystems may be provided with a
# place where they can place minimal amounts of persistent
# state. SSH keys or puppet certificates for example.
#
# Ideally we'll use puppet to manage the state directory and to
# create the bind mounts. However, until that's all ready this
# is sufficient to build a working system.
# First try to mount persistent data from /etc/fstab, then any
# partition with the proper label, then fallback to NFS
state_mount_dev=$(blkid -t LABEL="$STATE_LABEL" -l -o device)
if mount $mountopts $STATE_OPTIONS "$STATE_MOUNT" > /dev/null 2>&1 ; then
/bin/true
elif [ x$state_mount_dev != x ] && mount $state_mount_dev$mountopts "$STATE_MOUNT" > /dev/null 2>&1; then
/bin/true
elif [ ! -z "$CLIENTSTATE" ]; then
# No local storage was found. Make a final attempt to find
# state on an NFS server.
mount -t nfs $CLIENTSTATE/$HOSTNAME $STATE_MOUNT -o rw,nolock
fi
if [ -d $STATE_MOUNT/etc ]; then
# Copy the puppet CA's cert from the r/o image into the
# state directory so that we can create a bind mount on
# the ssl directory for storing the client cert. I'd really
# rather have a unionfs to deal with this stuff
cp --parents -f -p /var/lib/puppet/ssl/certs/ca.pem $STATE_MOUNT 2>/dev/null
# In the future this will be handled by puppet
for i in $(grep -v "^#" $STATE_MOUNT/files); do
if [ -e $i ]; then
mount -n -o bind $STATE_MOUNT/${i} ${i}
fi
done
fi
fi
再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow