首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >构建一个世界上最小的 Redis 镜像

构建一个世界上最小的 Redis 镜像

作者头像
米开朗基杨
发布2021-10-18 15:26:05
1.2K0
发布2021-10-18 15:26:05
举报
文章被收录于专栏:云原生实验室云原生实验室

好吧,我承认这么说可能违反了广告法,但是……它确实挺小的。

可以对比一组数据:

  • 官方的 Redis 镜像:105MB
  • 官方的基于 alpine 的 Redis 镜像:32.3MB
  • 在 ubuntu 下面用默认配置 Build 出来的 redis-server binary:13M
  • 一个什么都没有的 alpine:latest docker 镜像:5.6MB
  • 上图中的 Redis 镜像:1.69MB

所以……可以说,确实挺小了。

当然生产环境肯定不差 100M 这点空间,还是带上一些常用的工具在生产环境跑比较好。本文只是在玩 Nix 时候的自娱自乐,没有什么实际意义。

这个镜像是用 Nix build 的,实际上,就是玩了一下 Nix 网站上的 Cover Demo[1]。用到的手段有:

  1. 使用 Nix 来 build 这个 image;
  2. 编译的时候关闭了 systemd 的支持,Docker 里面不需要这种东西;
  3. 使用 musl 静态链接编译;
  4. 把除了 redis-server 之外的东西删除掉;
  5. 编译完成使用 strip -s 对最终的 binary 再次做删减。

具体的编译方法

首先在 Nix 创建一个文件,来编译 Redis,这里实际上使用的 Nix 打包好的 Redis,我只是对其通过 preBuildpostInstall 做了一些操作,替换 musl 和 strip 之类的。

[nix-shell:~]$ cat redis-minimal.nix
{ pkgs ? import <nixpkgs> {}
}:
pkgs.redis.overrideAttrs (old: {
  # no need for systemd support in our docker image
  makeFlags = old.makeFlags ++ ["USE_SYSTEMD=no"];
  # build static binary with musl
  preBuild = ''
    makeFlagsArray=(PREFIX="$out"
                    CC="${pkgs.musl.dev}/bin/musl-gcc -static"
                    CFLAGS="-I${pkgs.musl.dev}/include"
                    LDFLAGS="-L${pkgs.musl.dev}/lib")
  '';
  # Let's remove some binaries which we don't need
  postInstall = ''
     rm -f $out/bin/redis-{benchmark,check-*,cli,sentinel}
     strip -s $out/bin/redis-server
  '';
})

然后再需要一个文件描述如何 build docker image:

[nix-shell:~]$ cat docker-redis-minimal.nix
{ pkgs ? import <nixpkgs> { system = "x86_64-linux";}
}:                                   # nixpkgs package set
let
  redisMinimal = import ./redis-minimal.nix { inherit pkgs; };
in
pkgs.dockerTools.buildLayeredImage { # helper to build docker image
  name = "nix-redis-minimal";        # give docker image a name
  tag = "latest";                    # provide a tag
  contents = [ redisMinimal ];       # use redisMinimal package
}

非常简单,以至于不需要解释。

然后运行下面这个命令,build 就可以了。因为我已经 build 好了,所以 Nix 不会再出现 build 的日志。

[nix-shell:~]$ nix-build docker-redis-minimal.nix -o ./result
/nix/store/42frnm57499800z3mpwf05ab37mam1r0-docker-image-nix-redis-minimal.tar.gz

Docker (容器) 的原理[2] 曾经解释过,Docker image 本质上就是一个 tar 包。我们使用 docker load -i ./result 可以 load 这个 image。然后就可以运行了:

[nix-shell:~]$ docker load -i result
Loaded image: nix-redis-minimal:latest

[nix-shell:~/export-docker-image]$ docker images
REPOSITORY                TAG                 IMAGE ID            CREATED             SIZE
nix-redis-minimal         latest              433cad4ad790        51 years ago        1.69MB

[nix-shell:~]$ docker run nix-redis-minimal:latest redis-server
1:C 19 Jul 2021 16:37:09.847 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1:C 19 Jul 2021 16:37:09.847 # Redis version=5.0.7, bits=64, commit=00000000, modified=0, pid=1, just started
1:C 19 Jul 2021 16:37:09.847 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
1:M 19 Jul 2021 16:37:09.848 * Running mode=standalone, port=6379.
1:M 19 Jul 2021 16:37:09.848 # Server initialized
1:M 19 Jul 2021 16:37:09.848 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
1:M 19 Jul 2021 16:37:09.848 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.

可能你发现了这个 image 有一些奇怪:Created 51 years ago. 其实这是对的。因为 Nix 号称是完全 reproducible 的,但是 image 如果有一个创建时间的话,那么每次 build 出来的产物都会因为这个创建时间,而导致每次的产物 hash 都不一样。所以 Nix 将 Docker image 产物的 Created 时间设置成 0 了。即 timestamp = 0.

看看这个镜像里面都有什么?

读者可以在 Docker hub[3] 上下载这个镜像,然后使用 docker save 将它保存成 tar 再解压,看看里面都有什么。我这里直接去解压 Nix build 好的 image,每一层 layer 下面的 layer.tar 也都解压到对应的 layer 下面了。

可以看到,里面一层只有一个 redis-server 的 binary,上面一层是一个 bianry 的符号链接。符号链接是 Nix 的逻辑,符号链接很小,就懒得去删除了。

[nix-shell:~/export-docker-image]$ tree
.
├── 42frnm57499800z3mpwf05ab37mam1r0-docker-image-nix-redis-minimal.tar.gz
├── 433cad4ad790679879357e81194fa7502f7688edfe5b7ff64a4f59edfed3f84d.json
├── 83d967dde8785f9b8efc694109992e72f3a9ab6a1b953519e4b892633fd01b1d
│   ├── bin
│   │   └── redis-server -> /nix/store/h25xxpbif767cwhiqxk9z3gp1rbbx6fr-redis-5.0.7/bin/redis-server
│   ├── json
│   ├── layer.tar
│   └── VERSION
├── 8f7098124197b3823e91dd99eb3cd89853d3ec03448689f2a3f283b261551734
│   ├── json
│   ├── layer.tar
│   ├── nix
│   │   └── store
│   │       └── h25xxpbif767cwhiqxk9z3gp1rbbx6fr-redis-5.0.7
│   │           └── bin
│   │               └── redis-server
│   └── VERSION
├── manifest.json
└── repositories

7 directories, 12 files

体验这个镜像

我把这个镜像放到了 Docker hub[4] 上。可以直接运行 docker run laixintao/redis-minimal:v1 redis-server 来体验一下。

Docker 在 NixOS 里面的安装可以参考这里[5]

引用链接

[1]

Cover Demo: https://nixos.org/#asciinema-demo-cover

[2]

Docker (容器) 的原理: https://www.kawabangga.com/posts/4224

[3]

Docker hub: https://hub.docker.com/repository/docker/laixintao/redis-minimal

[4]

Docker hub: https://hub.docker.com/repository/docker/laixintao/redis-minimal

[5]

这里: https://nixos.wiki/wiki/Docker

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-10-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云原生实验室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 具体的编译方法
  • 看看这个镜像里面都有什么?
  • 体验这个镜像
    • 引用链接
    相关产品与服务
    云数据库 Redis
    腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档