Bug 1703082

Summary: The ubi-minimal image size is greater than ubi image only by updating packages
Product: Red Hat Enterprise Linux 7 Reporter: Carlos Rodríguez Hernández <crhernandez>
Component: ubi7-containerAssignee: Jindrich Novy <jnovy>
Status: CLOSED NOTABUG QA Contact: Martin Jenner <mjenner>
Severity: unspecified Docs Contact:
Priority: unspecified    
Version: 7.0CC: jwboyer
Target Milestone: rc   
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2019-08-23 11:58:24 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Attachments:
Description Flags
docker build logs none

Description Carlos Rodríguez Hernández 2019-04-25 13:27:23 UTC
Description of problem:

I found an unexpected behavior related to the `yum` VS `microdnf` commands and the size of the UBI images. 

Image	                Base size	Final size
UBI7	                203 MB	        686 MB
UBI7 (--disableplugin)	203 MB	        215 MB
UBI7-minimal	        79,1 MB	        233 MB

The number of packages installed by default is smaller in the minimal image (91) than the regular one (161):
```
$ docker run --rm -it registry.access.redhat.com/ubi7-dev-preview/ubi-minimal:latest rpm -qa | wc -l
91
$ docker run --rm -it registry.access.redhat.com/ubi7-dev-preview/ubi:latest rpm -qa | wc -l
161 
```

Inspecting the images, it seems the `microdnf update -y` command is updating and installing some packages that `yum --disableplugin=subscription-manager upgrade -y` is not.

The size difference with the UBI image with and without the subscription is clear for me, but I can not figure out why the size is even bigger using the minimal image.

The build without disabling the subscription-manager plugin was executed in a host subscribed to RHEL repositories, if I do the build in a host not subscribed to RHEL repositories, as expected, the size of the image is the same disabling or not the plugin.

How reproducible:

Using below Dockerfile to build an image based on the minimal image (79.1 MB) that updates the existing packages and installs curl:
```
FROM registry.access.redhat.com/ubi7-dev-preview/ubi-minimal
RUN microdnf update -y && microdnf install -y curl && microdnf clean all
```
the size of the image built is 233 MB.

Using the equivalent Dockerfile to build another image based on the non-minimal image (203 MB) and disabling the subscription
```
FROM registry.access.redhat.com/ubi7-dev-preview/ubi
RUN yum --disableplugin=subscription-manager upgrade -y && yum install --disableplugin=subscription-manager -y curl && rm -r /var/cache/yum
```
the size of the image is 215 MB. Using the same base image but without disabling the subscription-manager, the size is 686 MB.

The result is the same without installing curl.

Steps to Reproduce:

Building above Dockerfiles and comparing the image size using `docker images`

Actual results:

Only by updating the installed packages, the ubi image is greater than the ubi-minimal image.

Expected results:

Only by updating the installed packages, the ubi-minimal image should be smaller than the ubi image based on the size of the base image.

Comment 2 Carlos Rodríguez Hernández 2019-04-25 13:28:42 UTC
Created attachment 1558693 [details]
docker build logs

Comment 4 Josh Boyer 2019-06-12 15:28:54 UTC
Thanks for the report.  I was able to somewhat recreate the size issue locally using podman.  In summary, I believe what you are seeing is a side-effect of how RPM update transactions work.

In the minimal image case, glibc and glib2 are updated.  As part of that, those packages reinstall the i18n and locale and /usr/share/doc/ data that is explicitly removed during the base image build.  That adds roughly 22MB of data to the image.  glibc has some RPM scriptlets that regenerates /usr/lib/locale/locale-archive.tmpl which is over 100MB itself.  That file is also removed during the base image build.  There are a few other miscellaneous files that fall into this as well. 

Because these files are laid down during the update and not removed, the image size grows significantly.  On top of that, I don't believe docker squashes the layers by default so the overall image size is larger to account for the extra layer.  If I run the following command, I get a similar size image.

[jwboyer@zod tmp]$ cat Dockerfile 
FROM registry.access.redhat.com/ubi7-minimal:7.6-123
RUN microdnf update -y && microdnf install -y curl && microdnf -y clean all && rm -rf /usr/lib/locale/*.tmpl && for dir in locale i18n; do find /usr/share/${dir} -mindepth  1 -maxdepth 1 -type d -not \( -name "en_US" -o -name POSIX \) -exec rm -rf {} + ; done
[jwboyer@zod tmp]$ podman build . --squash --tag old-image:dnf-nolocale-squash2
STEP 1: FROM registry.access.redhat.com/ubi7-minimal:7.6-123
STEP 2: RUN microdnf update -y && microdnf install -y curl && microdnf -y clean all && rm -rf /usr/lib/locale/*.tmpl && for dir in locale i18n; do find /usr/share/${dir} -mindepth  1 -maxdepth 1 -type d -not \( -name "en_US" -o -name POSIX \) -exec rm -rf {} + ; done

(process:8): librhsm-WARNING **: 15:26:13.668: Found 0 entitlement certificates

(process:8): librhsm-WARNING **: 15:26:13.671: Found 0 entitlement certificates
Downloading metadata...
Downloading metadata...
Downloading metadata...
Downloading metadata...
Transaction: 3 packages
glibc-common-2.17-260.el7_6.6.x86_64 (ubi-7)
glibc-2.17-260.el7_6.6.x86_64 (ubi-7)
glib2-2.56.1-4.el7_6.x86_64 (ubi-7)
Downloading packages...
Running transaction test...
Updating: glibc;2.17-260.el7_6.6;x86_64;ubi-7
Updating: glibc-common;2.17-260.el7_6.6;x86_64;ubi-7
/usr/sbin/build-locale-archive: cannot resize archive file: Too many open files
/usr/sbin/build-locale-archive: cannot resize archive file: Too many open files
Updating: glib2;2.56.1-4.el7_6;x86_64;ubi-7
Cleanup: glib2;2.56.1-2.el7;x86_64;installed
Cleanup: glibc;2.17-260.el7_6.4;x86_64;installed
Cleanup: glibc-common;2.17-260.el7_6.4;x86_64;installed
Complete.

(process:65): librhsm-WARNING **: 15:26:34.441: Found 0 entitlement certificates

(process:65): librhsm-WARNING **: 15:26:34.444: Found 0 entitlement certificates
Downloading metadata...
Downloading metadata...
Downloading metadata...
Downloading metadata...
Nothing to do.

(process:107): librhsm-WARNING **: 15:26:39.001: Found 0 entitlement certificates

(process:107): librhsm-WARNING **: 15:26:39.003: Found 0 entitlement certificates
Complete.
STEP 3: COMMIT old-image:dnf-nolocale-squash2
--> 1c77df1699c5e51c78cc250bb6f7e9d70f1ed0033933c3cf8efe00c8cc9f063f
[jwboyer@zod tmp]$ podman images
REPOSITORY                                        TAG                    IMAGE ID       CREATED          SIZE
localhost/old-image                               dnf-nolocale-squash2   1c77df1699c5   12 seconds ago   83.1 MB
registry.access.redhat.com/ubi7-minimal           7.6-123                8d0998e077d3   8 weeks ago      83 MB
[jwboyer@zod tmp]$

Comment 5 Josh Boyer 2019-08-23 11:58:24 UTC
Closing this bug out.  There are a few ways to mitigate the size explosion when performing yum update documented above, and the situation should already be better with ubi8.  Primarily though, it would be better to pull the latest container from the registry instead of running yum update within an existing image.