1
0
mirror of https://github.com/rancher/os.git synced 2025-08-01 06:59:05 +00:00

Optimize image loading to reduce memory footprint and boot time

This commit is contained in:
Jan B 2018-09-09 10:07:50 +02:00 committed by niusmallnan
parent dcce547bad
commit e5b1643bfa
7 changed files with 67 additions and 57 deletions

View File

@ -21,7 +21,8 @@ const (
SystemDockerHost = "unix:///var/run/system-docker.sock"
DockerHost = "unix:///var/run/docker.sock"
ImagesPath = "/usr/share/ros"
ImagesPattern = "images*.tar"
InitImages = "images-init.tar"
SystemImages = "images-system.tar"
ModulesArchive = "/modules.tar"
Debug = false
SystemDockerLog = "/var/log/system-docker.log"

View File

@ -68,7 +68,7 @@ func bootstrap(cfg *config.CloudConfig) error {
_, err = config.ChainCfgFuncs(cfg,
[]config.CfgFuncData{
config.CfgFuncData{"bootstrap loadImages", loadImages},
config.CfgFuncData{"bootstrap loadImages", loadBootstrapImages},
config.CfgFuncData{"bootstrap Services", bootstrapServices},
})
return err
@ -84,7 +84,7 @@ func runCloudInitServices(cfg *config.CloudConfig) error {
_, err = config.ChainCfgFuncs(cfg,
[]config.CfgFuncData{
config.CfgFuncData{"cloudinit loadImages", loadImages},
config.CfgFuncData{"cloudinit loadImages", loadBootstrapImages},
config.CfgFuncData{"cloudinit Services", runCloudInitServiceSet},
})
return err

View File

@ -87,7 +87,7 @@ func recovery(initFailure error) {
_, err = config.ChainCfgFuncs(&recoveryConfig,
[]config.CfgFuncData{
config.CfgFuncData{"loadImages", loadImages},
config.CfgFuncData{"loadSystemImages", loadSystemImages},
config.CfgFuncData{"recovery console", recoveryServices},
})
if err != nil {

View File

@ -4,6 +4,7 @@ import (
"os"
"os/exec"
"path"
"path/filepath"
"syscall"
"golang.org/x/net/context"
@ -29,62 +30,47 @@ func hasImage(name string) bool {
return true
}
func findImages(cfg *config.CloudConfig) ([]string, error) {
log.Debugf("Looking for images at %s", config.ImagesPath)
result := []string{}
dir, err := os.Open(config.ImagesPath)
if os.IsNotExist(err) {
log.Debugf("Not loading images, %s does not exist", config.ImagesPath)
return result, nil
}
if err != nil {
return nil, err
func getImagesArchive(bootstrap bool) string {
var archive string
if bootstrap {
archive = path.Join(config.ImagesPath, config.InitImages)
} else {
archive = path.Join(config.ImagesPath, config.SystemImages)
}
defer dir.Close()
files, err := dir.Readdirnames(0)
if err != nil {
return nil, err
}
for _, fileName := range files {
if ok, _ := path.Match(config.ImagesPattern, fileName); ok {
log.Debugf("Found %s", fileName)
result = append(result, fileName)
}
}
return result, nil
return archive
}
func loadImages(cfg *config.CloudConfig) (*config.CloudConfig, error) {
images, err := findImages(cfg)
if err != nil || len(images) == 0 {
return cfg, err
}
func loadBootstrapImages(cfg *config.CloudConfig) (*config.CloudConfig, error) {
return loadImages(cfg, true)
}
func loadSystemImages(cfg *config.CloudConfig) (*config.CloudConfig, error) {
return loadImages(cfg, false)
}
func loadImages(cfg *config.CloudConfig, bootstrap bool) (*config.CloudConfig, error) {
archive := getImagesArchive(bootstrap)
client, err := docker.NewSystemClient()
if err != nil {
return cfg, err
}
for _, image := range images {
if hasImage(image) {
continue
if !hasImage(filepath.Base(archive)) {
if _, err := os.Stat(archive); os.IsNotExist(err) {
log.Fatalf("FATAL: Could not load images from %s (file not found)", archive)
}
// client.ImageLoad is an asynchronous operation
// To ensure the order of execution, use cmd instead of it
inputFileName := path.Join(config.ImagesPath, image)
log.Infof("Loading images from %s", inputFileName)
if err = exec.Command("/usr/bin/system-docker", "load", "-q", "-i", inputFileName).Run(); err != nil {
log.Fatalf("FATAL: failed loading images from %s: %s", inputFileName, err)
log.Infof("Loading images from %s", archive)
cmd := exec.Command("/usr/bin/system-docker", "load", "-q", "-i", archive)
if out, err := cmd.CombinedOutput(); err != nil {
log.Fatalf("FATAL: Error loading images from %s (%v)\n%s ", archive, err, out)
}
log.Infof("Done loading images from %s", inputFileName)
log.Infof("Done loading images from %s", archive)
}
dockerImages, _ := client.ImageList(context.Background(), types.ImageListOptions{})
@ -104,7 +90,7 @@ func SysInit() error {
_, err := config.ChainCfgFuncs(cfg,
[]config.CfgFuncData{
config.CfgFuncData{"loadImages", loadImages},
config.CfgFuncData{"loadSystemImages", loadSystemImages},
config.CfgFuncData{"start project", func(cfg *config.CloudConfig) (*config.CloudConfig, error) {
p, err := compose.GetProject(cfg, false, true)
if err != nil {

View File

@ -7,7 +7,7 @@ mkdir -p ${INITRD_DIR}/usr/{etc,lib,bin,share/ros}
./scripts/template
cp -rf assets/selinux ${INITRD_DIR}/usr/etc
cp build/images.tar ${INITRD_DIR}/usr/share/ros/
cp build/images*.tar ${INITRD_DIR}/usr/share/ros/
cp bin/ros ${INITRD_DIR}/usr/bin/
ln -s usr/bin/ros ${INITRD_DIR}/init
ln -s bin ${INITRD_DIR}/usr/sbin

View File

@ -12,24 +12,28 @@ PREPOP_DIR=${IMAGE_CACHE}/var/lib/system-docker
INITRD_DIR=${BUILD}/initrd
ARTIFACTS=$(pwd)/dist/artifacts
INITRD=${ARTIFACTS}/initrd
INIT_IMAGES="images-init.tar"
SYSTEM_IMAGES="images-system.tar"
mkdir -p ${ARTIFACTS} ${PREPOP_DIR}
if [ "$(docker info | grep 'Storage Driver: ' | sed 's/Storage Driver: //')" != "overlay" ]; then
echo Overlay storage driver is required to prepackage exploded images
echo packaging images.tar instead
echo Overlay storage driver is require to prepackage exploded images
echo packaging image tar archives instead
tar czf ${ARTIFACTS}/rootfs${SUFFIX}.tar.gz --exclude lib/modules --exclude lib/firmware -C ${INITRD_DIR} .
exit 0
fi
DFS=$(docker run -d --privileged -v /lib/modules/$(uname -r):/lib/modules/$(uname -r) ${DFS_IMAGE}${SUFFIX} ${DFS_ARGS})
trap "docker rm -fv ${DFS_ARCH} ${DFS}" EXIT
docker exec -i ${DFS} docker load < ${INITRD_DIR}/usr/share/ros/images.tar
docker exec -i ${DFS} docker load < ${INITRD_DIR}/usr/share/ros/${INIT_IMAGES}
docker exec -i ${DFS} docker load < ${INITRD_DIR}/usr/share/ros/${SYSTEM_IMAGES}
docker stop ${DFS}
docker run --rm --volumes-from=${DFS} --entrypoint /bin/bash rancher/os-base -c "tar -c -C /var/lib/docker ./image" | tar -x -C ${PREPOP_DIR}
docker run --rm --volumes-from=${DFS} --entrypoint /bin/bash rancher/os-base -c "tar -c -C /var/lib/docker ./overlay" | tar -x -C ${PREPOP_DIR}
tar -cf ${ARTIFACTS}/rootfs${SUFFIX}.tar --exclude usr/share/ros/images.tar --exclude lib/modules --exclude lib/firmware -C ${INITRD_DIR} .
tar -cf ${ARTIFACTS}/rootfs${SUFFIX}.tar --exclude usr/share/ros/${INIT_IMAGES} --exclude usr/share/ros/${SYSTEM_IMAGES} --exclude lib/modules --exclude
lib/firmware -C ${INITRD_DIR} .
tar -rf ${ARTIFACTS}/rootfs${SUFFIX}.tar -C ${IMAGE_CACHE} .
rm -f ${ARTIFACTS}/rootfs${SUFFIX}.tar.gz
gzip ${ARTIFACTS}/rootfs${SUFFIX}.tar

View File

@ -1,29 +1,48 @@
#!/bin/bash
set -ex
INIT_DEP="rancher/os-bootstrap"
SHARED_DEP="rancher/os-base"
INIT_IMAGES_DST="build/images-init.tar"
SYSTEM_IMAGES_DST="build/images-system.tar"
cd $(dirname $0)/..
IMAGES=$(bin/host_ros c images -i build/initrd/usr/share/ros/os-config.yml)
echo "tar-image: IMAGES=$IMAGES"
for i in $IMAGES; do
INIT_IMAGES=""
SYSTEM_IMAGES=""
for i in ${IMAGES}; do
echo "tar-image: pull($i)"
if [ "${FORCE_PULL}" = "1" ] || ! docker inspect $i >/dev/null 2>&1; then
docker pull $i
docker pull ${i}
fi
if [ "${i%%:*}" != "$INIT_DEP" ] ; then
SYSTEM_IMAGES="$SYSTEM_IMAGES $i"
fi
if [ "${i%%:*}" = "$INIT_DEP" ] || [ "${i%%:*}" = "$SHARED_DEP" ] ; then
INIT_IMAGES="$INIT_IMAGES $i"
fi
done
if [ -e ".make-vmware" ]; then
docker pull rancher/os-openvmtools:${OPEN_VMTOOLS_VERSION}
IMAGES="$IMAGES rancher/os-openvmtools:${OPEN_VMTOOLS_VERSION}"
SYSTEM_IMAGES="$SYSTEM_IMAGES rancher/os-openvmtools:${OPEN_VMTOOLS_VERSION}"
fi
echo "tar-images: docker save ${IMAGES}"
echo "tar-image: SYSTEM_IMAGES=$SYSTEM_IMAGES"
echo "tar-image: INIT_IMAGES=$INIT_IMAGES"
if [ "$COMPRESS" == "" ]; then
docker save ${IMAGES} | gzip > build/images.tar
ARCHIVE_CMD="gzip"
else
# system-docker can not load images which compressed by xz with a compression level of 9
# decompression consumes more memory if using level 9
# the default compression level for xz is 6
docker save ${IMAGES} | xz -6 -e > build/images.tar
ARCHIVE_CMD="xz -4 -e"
fi
docker save ${INIT_IMAGES} | ${ARCHIVE_CMD} > ${INIT_IMAGES_DST}
docker save ${SYSTEM_IMAGES} | ${ARCHIVE_CMD} > ${SYSTEM_IMAGES_DST}
echo "tar-images: DONE"