mirror of
https://github.com/rancher/os.git
synced 2025-08-10 02:58:15 +00:00
Optimize image loading to reduce memory footprint and boot time
This commit is contained in:
parent
dcce547bad
commit
e5b1643bfa
@ -21,7 +21,8 @@ const (
|
|||||||
SystemDockerHost = "unix:///var/run/system-docker.sock"
|
SystemDockerHost = "unix:///var/run/system-docker.sock"
|
||||||
DockerHost = "unix:///var/run/docker.sock"
|
DockerHost = "unix:///var/run/docker.sock"
|
||||||
ImagesPath = "/usr/share/ros"
|
ImagesPath = "/usr/share/ros"
|
||||||
ImagesPattern = "images*.tar"
|
InitImages = "images-init.tar"
|
||||||
|
SystemImages = "images-system.tar"
|
||||||
ModulesArchive = "/modules.tar"
|
ModulesArchive = "/modules.tar"
|
||||||
Debug = false
|
Debug = false
|
||||||
SystemDockerLog = "/var/log/system-docker.log"
|
SystemDockerLog = "/var/log/system-docker.log"
|
||||||
|
@ -68,7 +68,7 @@ func bootstrap(cfg *config.CloudConfig) error {
|
|||||||
|
|
||||||
_, err = config.ChainCfgFuncs(cfg,
|
_, err = config.ChainCfgFuncs(cfg,
|
||||||
[]config.CfgFuncData{
|
[]config.CfgFuncData{
|
||||||
config.CfgFuncData{"bootstrap loadImages", loadImages},
|
config.CfgFuncData{"bootstrap loadImages", loadBootstrapImages},
|
||||||
config.CfgFuncData{"bootstrap Services", bootstrapServices},
|
config.CfgFuncData{"bootstrap Services", bootstrapServices},
|
||||||
})
|
})
|
||||||
return err
|
return err
|
||||||
@ -84,7 +84,7 @@ func runCloudInitServices(cfg *config.CloudConfig) error {
|
|||||||
|
|
||||||
_, err = config.ChainCfgFuncs(cfg,
|
_, err = config.ChainCfgFuncs(cfg,
|
||||||
[]config.CfgFuncData{
|
[]config.CfgFuncData{
|
||||||
config.CfgFuncData{"cloudinit loadImages", loadImages},
|
config.CfgFuncData{"cloudinit loadImages", loadBootstrapImages},
|
||||||
config.CfgFuncData{"cloudinit Services", runCloudInitServiceSet},
|
config.CfgFuncData{"cloudinit Services", runCloudInitServiceSet},
|
||||||
})
|
})
|
||||||
return err
|
return err
|
||||||
|
@ -87,7 +87,7 @@ func recovery(initFailure error) {
|
|||||||
|
|
||||||
_, err = config.ChainCfgFuncs(&recoveryConfig,
|
_, err = config.ChainCfgFuncs(&recoveryConfig,
|
||||||
[]config.CfgFuncData{
|
[]config.CfgFuncData{
|
||||||
config.CfgFuncData{"loadImages", loadImages},
|
config.CfgFuncData{"loadSystemImages", loadSystemImages},
|
||||||
config.CfgFuncData{"recovery console", recoveryServices},
|
config.CfgFuncData{"recovery console", recoveryServices},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
|
"path/filepath"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
@ -29,62 +30,47 @@ func hasImage(name string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func findImages(cfg *config.CloudConfig) ([]string, error) {
|
func getImagesArchive(bootstrap bool) string {
|
||||||
log.Debugf("Looking for images at %s", config.ImagesPath)
|
var archive string
|
||||||
|
if bootstrap {
|
||||||
result := []string{}
|
archive = path.Join(config.ImagesPath, config.InitImages)
|
||||||
|
} else {
|
||||||
dir, err := os.Open(config.ImagesPath)
|
archive = path.Join(config.ImagesPath, config.SystemImages)
|
||||||
if os.IsNotExist(err) {
|
|
||||||
log.Debugf("Not loading images, %s does not exist", config.ImagesPath)
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
defer dir.Close()
|
return archive
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadImages(cfg *config.CloudConfig) (*config.CloudConfig, error) {
|
func loadBootstrapImages(cfg *config.CloudConfig) (*config.CloudConfig, error) {
|
||||||
images, err := findImages(cfg)
|
return loadImages(cfg, true)
|
||||||
if err != nil || len(images) == 0 {
|
}
|
||||||
return cfg, err
|
|
||||||
}
|
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()
|
client, err := docker.NewSystemClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cfg, err
|
return cfg, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, image := range images {
|
if !hasImage(filepath.Base(archive)) {
|
||||||
if hasImage(image) {
|
if _, err := os.Stat(archive); os.IsNotExist(err) {
|
||||||
continue
|
log.Fatalf("FATAL: Could not load images from %s (file not found)", archive)
|
||||||
}
|
}
|
||||||
|
|
||||||
// client.ImageLoad is an asynchronous operation
|
// client.ImageLoad is an asynchronous operation
|
||||||
// To ensure the order of execution, use cmd instead of it
|
// To ensure the order of execution, use cmd instead of it
|
||||||
inputFileName := path.Join(config.ImagesPath, image)
|
log.Infof("Loading images from %s", archive)
|
||||||
log.Infof("Loading images from %s", inputFileName)
|
cmd := exec.Command("/usr/bin/system-docker", "load", "-q", "-i", archive)
|
||||||
if err = exec.Command("/usr/bin/system-docker", "load", "-q", "-i", inputFileName).Run(); err != nil {
|
if out, err := cmd.CombinedOutput(); err != nil {
|
||||||
log.Fatalf("FATAL: failed loading images from %s: %s", inputFileName, err)
|
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{})
|
dockerImages, _ := client.ImageList(context.Background(), types.ImageListOptions{})
|
||||||
@ -104,7 +90,7 @@ func SysInit() error {
|
|||||||
|
|
||||||
_, err := config.ChainCfgFuncs(cfg,
|
_, err := config.ChainCfgFuncs(cfg,
|
||||||
[]config.CfgFuncData{
|
[]config.CfgFuncData{
|
||||||
config.CfgFuncData{"loadImages", loadImages},
|
config.CfgFuncData{"loadSystemImages", loadSystemImages},
|
||||||
config.CfgFuncData{"start project", func(cfg *config.CloudConfig) (*config.CloudConfig, error) {
|
config.CfgFuncData{"start project", func(cfg *config.CloudConfig) (*config.CloudConfig, error) {
|
||||||
p, err := compose.GetProject(cfg, false, true)
|
p, err := compose.GetProject(cfg, false, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -7,7 +7,7 @@ mkdir -p ${INITRD_DIR}/usr/{etc,lib,bin,share/ros}
|
|||||||
./scripts/template
|
./scripts/template
|
||||||
|
|
||||||
cp -rf assets/selinux ${INITRD_DIR}/usr/etc
|
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/
|
cp bin/ros ${INITRD_DIR}/usr/bin/
|
||||||
ln -s usr/bin/ros ${INITRD_DIR}/init
|
ln -s usr/bin/ros ${INITRD_DIR}/init
|
||||||
ln -s bin ${INITRD_DIR}/usr/sbin
|
ln -s bin ${INITRD_DIR}/usr/sbin
|
||||||
|
@ -12,24 +12,28 @@ PREPOP_DIR=${IMAGE_CACHE}/var/lib/system-docker
|
|||||||
INITRD_DIR=${BUILD}/initrd
|
INITRD_DIR=${BUILD}/initrd
|
||||||
ARTIFACTS=$(pwd)/dist/artifacts
|
ARTIFACTS=$(pwd)/dist/artifacts
|
||||||
INITRD=${ARTIFACTS}/initrd
|
INITRD=${ARTIFACTS}/initrd
|
||||||
|
INIT_IMAGES="images-init.tar"
|
||||||
|
SYSTEM_IMAGES="images-system.tar"
|
||||||
|
|
||||||
mkdir -p ${ARTIFACTS} ${PREPOP_DIR}
|
mkdir -p ${ARTIFACTS} ${PREPOP_DIR}
|
||||||
|
|
||||||
if [ "$(docker info | grep 'Storage Driver: ' | sed 's/Storage Driver: //')" != "overlay" ]; then
|
if [ "$(docker info | grep 'Storage Driver: ' | sed 's/Storage Driver: //')" != "overlay" ]; then
|
||||||
echo Overlay storage driver is required to prepackage exploded images
|
echo Overlay storage driver is require to prepackage exploded images
|
||||||
echo packaging images.tar instead
|
echo packaging image tar archives instead
|
||||||
tar czf ${ARTIFACTS}/rootfs${SUFFIX}.tar.gz --exclude lib/modules --exclude lib/firmware -C ${INITRD_DIR} .
|
tar czf ${ARTIFACTS}/rootfs${SUFFIX}.tar.gz --exclude lib/modules --exclude lib/firmware -C ${INITRD_DIR} .
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
DFS=$(docker run -d --privileged -v /lib/modules/$(uname -r):/lib/modules/$(uname -r) ${DFS_IMAGE}${SUFFIX} ${DFS_ARGS})
|
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
|
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 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 ./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}
|
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} .
|
tar -rf ${ARTIFACTS}/rootfs${SUFFIX}.tar -C ${IMAGE_CACHE} .
|
||||||
rm -f ${ARTIFACTS}/rootfs${SUFFIX}.tar.gz
|
rm -f ${ARTIFACTS}/rootfs${SUFFIX}.tar.gz
|
||||||
gzip ${ARTIFACTS}/rootfs${SUFFIX}.tar
|
gzip ${ARTIFACTS}/rootfs${SUFFIX}.tar
|
||||||
|
@ -1,29 +1,48 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -ex
|
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)/..
|
cd $(dirname $0)/..
|
||||||
|
|
||||||
IMAGES=$(bin/host_ros c images -i build/initrd/usr/share/ros/os-config.yml)
|
IMAGES=$(bin/host_ros c images -i build/initrd/usr/share/ros/os-config.yml)
|
||||||
echo "tar-image: IMAGES=$IMAGES"
|
INIT_IMAGES=""
|
||||||
for i in $IMAGES; do
|
SYSTEM_IMAGES=""
|
||||||
|
for i in ${IMAGES}; do
|
||||||
echo "tar-image: pull($i)"
|
echo "tar-image: pull($i)"
|
||||||
if [ "${FORCE_PULL}" = "1" ] || ! docker inspect $i >/dev/null 2>&1; then
|
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
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ -e ".make-vmware" ]; then
|
if [ -e ".make-vmware" ]; then
|
||||||
docker pull rancher/os-openvmtools:${OPEN_VMTOOLS_VERSION}
|
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
|
fi
|
||||||
|
|
||||||
echo "tar-images: docker save ${IMAGES}"
|
echo "tar-image: SYSTEM_IMAGES=$SYSTEM_IMAGES"
|
||||||
|
echo "tar-image: INIT_IMAGES=$INIT_IMAGES"
|
||||||
|
|
||||||
if [ "$COMPRESS" == "" ]; then
|
if [ "$COMPRESS" == "" ]; then
|
||||||
docker save ${IMAGES} | gzip > build/images.tar
|
ARCHIVE_CMD="gzip"
|
||||||
else
|
else
|
||||||
# system-docker can not load images which compressed by xz with a compression level of 9
|
# system-docker can not load images which compressed by xz with a compression level of 9
|
||||||
# decompression consumes more memory if using level 9
|
# decompression consumes more memory if using level 9
|
||||||
# the default compression level for xz is 6
|
# the default compression level for xz is 6
|
||||||
docker save ${IMAGES} | xz -6 -e > build/images.tar
|
ARCHIVE_CMD="xz -4 -e"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
docker save ${INIT_IMAGES} | ${ARCHIVE_CMD} > ${INIT_IMAGES_DST}
|
||||||
|
docker save ${SYSTEM_IMAGES} | ${ARCHIVE_CMD} > ${SYSTEM_IMAGES_DST}
|
||||||
echo "tar-images: DONE"
|
echo "tar-images: DONE"
|
||||||
|
Loading…
Reference in New Issue
Block a user