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:
parent
dcce547bad
commit
e5b1643bfa
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user