Skip to content

Commit 4b50ca0

Browse files
committed
Extract deb and rpm packages to single image
This change swithces to using a single image for the NVIDIA Container Toolkit contianer. Here the contents of the architecture-specific deb and rpm packages are extracted to a known root. These contents can then be installed using the updated installation mechanism which has been updated to detect the source root based on the packaging type. Signed-off-by: Evan Lezar <[email protected]>
1 parent a2e2a44 commit 4b50ca0

File tree

7 files changed

+164
-32
lines changed

7 files changed

+164
-32
lines changed

cmd/nvidia-ctk-installer/main.go

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,11 @@ var signalReceived = make(chan bool, 1)
3636
type options struct {
3737
toolkitInstallDir string
3838

39-
noDaemon bool
40-
runtime string
41-
pidFile string
42-
sourceRoot string
39+
noDaemon bool
40+
runtime string
41+
pidFile string
42+
sourceRoot string
43+
packageType string
4344

4445
toolkitOptions toolkit.Options
4546
runtimeOptions runtime.Options
@@ -123,11 +124,17 @@ func (a app) build() *cli.App {
123124
EnvVars: []string{"TOOLKIT_INSTALL_DIR", "ROOT"},
124125
},
125126
&cli.StringFlag{
126-
Name: "source-root",
127-
Value: "/",
128-
Usage: "The folder where the required toolkit artifacts can be found",
127+
Name: "toolkit-source-root",
128+
Usage: "The folder where the required toolkit artifacts can be found. If this is not specified, the path /artifacts/{{ .ToolkitPackageType }} is used where ToolkitPackageType is the resolved package type",
129129
Destination: &options.sourceRoot,
130-
EnvVars: []string{"SOURCE_ROOT"},
130+
EnvVars: []string{"TOOLKIT_SOURCE_ROOT"},
131+
},
132+
&cli.StringFlag{
133+
Name: "toolkit-package-type",
134+
Usage: "specify the package type to use for the toolkit. One of ['deb', 'rpm', 'auto', '']. If 'auto' or '' are used, the type is inferred automatically.",
135+
Value: "auto",
136+
Destination: &options.packageType,
137+
EnvVars: []string{"TOOLKIT_PACKAGE_TYPE"},
131138
},
132139
&cli.StringFlag{
133140
Name: "pid-file",
@@ -145,6 +152,15 @@ func (a app) build() *cli.App {
145152
}
146153

147154
func (a *app) Before(c *cli.Context, o *options) error {
155+
if o.sourceRoot == "" {
156+
sourceRoot, err := resolveSourceRoot(o.runtimeOptions.HostRootMount, o.packageType)
157+
if err != nil {
158+
return fmt.Errorf("failed to resolve source root: %v", err)
159+
}
160+
a.logger.Infof("Resolved source root to %v", sourceRoot)
161+
o.sourceRoot = sourceRoot
162+
}
163+
148164
a.toolkit = toolkit.NewInstaller(
149165
toolkit.WithLogger(a.logger),
150166
toolkit.WithSourceRoot(o.sourceRoot),
@@ -277,3 +293,33 @@ func (a *app) shutdown(pidFile string) {
277293
a.logger.Warningf("Unable to remove pidfile: %v", err)
278294
}
279295
}
296+
297+
func resolveSourceRoot(hostRoot string, packageType string) (string, error) {
298+
resolvedPackageType, err := resolvePackageType(hostRoot, packageType)
299+
if err != nil {
300+
return "", err
301+
}
302+
switch resolvedPackageType {
303+
case "deb":
304+
return "/artifacts/deb", nil
305+
case "rpm":
306+
return "/artifacts/rpm", nil
307+
default:
308+
return "", fmt.Errorf("invalid package type: %v", resolvedPackageType)
309+
}
310+
}
311+
312+
func resolvePackageType(hostRoot string, packageType string) (rPackageTypes string, rerr error) {
313+
if packageType != "" && packageType != "auto" {
314+
return packageType, nil
315+
}
316+
317+
if info, err := os.Stat(filepath.Join(hostRoot, "/usr/bin/rpm")); err != nil && !info.IsDir() {
318+
return "rpm", nil
319+
}
320+
if info, err := os.Stat(filepath.Join(hostRoot, "/usr/bin/dpkg")); err != nil && !info.IsDir() {
321+
return "deb", nil
322+
}
323+
324+
return "deb", nil
325+
}

cmd/nvidia-ctk-installer/main_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ swarm-resource = ""
418418
"--driver-root-ctr-path=" + hostRoot,
419419
"--pid-file=" + filepath.Join(testRoot, "toolkit.pid"),
420420
"--restart-mode=none",
421-
"--source-root=" + filepath.Join(artifactRoot, "deb"),
421+
"--toolkit-source-root=" + filepath.Join(artifactRoot, "deb"),
422422
}
423423

424424
err := app.Run(append(testArgs, tc.args...))

cmd/nvidia-ctk-installer/toolkit/installer/installer.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,16 @@ var _ Installer = (*toolkitInstaller)(nil)
4747

4848
// New creates a toolkit installer with the specified options.
4949
func New(opts ...Option) (Installer, error) {
50-
t := &toolkitInstaller{}
50+
t := &toolkitInstaller{
51+
sourceRoot: "/",
52+
}
5153
for _, opt := range opts {
5254
opt(t)
5355
}
5456

5557
if t.logger == nil {
5658
t.logger = logger.New()
5759
}
58-
if t.sourceRoot == "" {
59-
t.sourceRoot = "/"
60-
}
6160
if t.artifactRoot == nil {
6261
artifactRoot, err := newArtifactRoot(t.logger, t.sourceRoot)
6362
if err != nil {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
*
3+
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
*
18+
*/
19+
package installer

cmd/nvidia-ctk-installer/toolkit/toolkit.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,8 @@ func Flags(opts *Options) []cli.Flag {
215215

216216
// An Installer is used to install the NVIDIA Container Toolkit from the toolkit container.
217217
type Installer struct {
218-
logger logger.Interface
218+
logger logger.Interface
219+
219220
sourceRoot string
220221
// toolkitRoot specifies the destination path at which the toolkit is installed.
221222
toolkitRoot string

deployments/container/Dockerfile.ubi8

Lines changed: 75 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -47,33 +47,92 @@ ARG VERSION="N/A"
4747
ARG GIT_COMMIT="unknown"
4848
RUN make PREFIX=/artifacts cmd-nvidia-ctk-installer
4949

50-
FROM nvcr.io/nvidia/cuda:12.8.1-base-ubi8
51-
52-
ENV NVIDIA_DISABLE_REQUIRE="true"
53-
ENV NVIDIA_VISIBLE_DEVICES=void
54-
ENV NVIDIA_DRIVER_CAPABILITIES=utility
50+
# The packaging stage collects the deb and rpm packages built for supported
51+
# architectures.
52+
FROM nvcr.io/nvidia/cuda:12.8.1-base-ubi8 AS packaging
5553

5654
ARG ARTIFACTS_ROOT
57-
ARG PACKAGE_DIST
58-
COPY ${ARTIFACTS_ROOT}/${PACKAGE_DIST} /artifacts/packages/${PACKAGE_DIST}
55+
COPY ${ARTIFACTS_ROOT} /artifacts/packages/
5956

6057
WORKDIR /artifacts/packages
6158

59+
# build-args are added to the manifest.txt file below.
60+
ARG PACKAGE_DIST
6261
ARG PACKAGE_VERSION
62+
ARG GIT_BRANCH
63+
ARG GIT_COMMIT
64+
ARG GIT_COMMIT_SHORT
65+
ARG SOURCE_DATE_EPOCH
66+
ARG VERSION
67+
68+
# Create a manifest.txt file with the absolute paths of all deb and rpm packages in the container
69+
RUN echo "#IMAGE_EPOCH=$(date '+%s')" > /artifacts/manifest.txt && \
70+
env | sed 's/^/#/g' >> /artifacts/manifest.txt && \
71+
find /artifacts/packages -iname '*.deb' -o -iname '*.rpm' >> /artifacts/manifest.txt
72+
73+
RUN mkdir /licenses && mv /NGC-DL-CONTAINER-LICENSE /licenses/NGC-DL-CONTAINER-LICENSE
74+
75+
# The debpackages stage is used to extract the contents of deb packages.
76+
FROM nvcr.io/nvidia/cuda:12.8.1-base-ubuntu20.04 AS debpackages
77+
6378
ARG TARGETARCH
64-
ENV PACKAGE_ARCH=${TARGETARCH}
79+
ARG PACKAGE_DIST_DEB=ubuntu18.04
6580

66-
RUN PACKAGE_ARCH=${PACKAGE_ARCH/amd64/x86_64} && PACKAGE_ARCH=${PACKAGE_ARCH/arm64/aarch64} && \
67-
yum localinstall -y \
68-
${PACKAGE_DIST}/${PACKAGE_ARCH}/libnvidia-container1-1.*.rpm \
69-
${PACKAGE_DIST}/${PACKAGE_ARCH}/libnvidia-container-tools-1.*.rpm \
70-
${PACKAGE_DIST}/${PACKAGE_ARCH}/nvidia-container-toolkit*-${PACKAGE_VERSION}*.rpm
81+
COPY --from=packaging /artifacts/packages/${PACKAGE_DIST_DEB} /deb-packages
7182

72-
WORKDIR /work
83+
RUN mkdir -p /artifacts/deb
84+
RUN set -eux; \
85+
\
86+
case "${TARGETARCH}" in \
87+
x86_64 | amd64) ARCH='amd64' ;; \
88+
ppc64el | ppc64le) ARCH='ppc64le' ;; \
89+
aarch64 | arm64) ARCH='arm64' ;; \
90+
*) echo "unsupported architecture" ; exit 1 ;; \
91+
esac; \
92+
for p in $(ls /deb-packages/${ARCH}/*.deb); do dpkg-deb -xv $p /artifacts/deb/; done
93+
94+
# The rpmpackages stage is used to extract the contents of the rpm packages.
95+
FROM nvcr.io/nvidia/cuda:12.8.1-base-ubi8 AS rpmpackages
96+
RUN dnf install -y cpio
97+
98+
ARG TARGETARCH
99+
ARG PACKAGE_DIST_RPM=centos7
100+
101+
COPY --from=packaging /artifacts/packages/${PACKAGE_DIST_RPM} /rpm-packages
102+
103+
RUN mkdir -p /artifacts/rpm
104+
RUN set -eux; \
105+
\
106+
case "${TARGETARCH}" in \
107+
x86_64 | amd64) ARCH='x86_64' ;; \
108+
ppc64el | ppc64le) ARCH='ppc64le' ;; \
109+
aarch64 | arm64) ARCH='aarch64' ;; \
110+
*) echo "unsupported architecture" ; exit 1 ;; \
111+
esac; \
112+
for p in $(ls /rpm-packages/${ARCH}/*.rpm); do rpm2cpio $p | cpio -idmv -D /artifacts/rpm; done
113+
114+
# The artifacts image serves as an intermediate stage to collect the artifacts
115+
# From the previous stages:
116+
# - The extracted deb packages
117+
# - The extracted rpm packages
118+
# - The nvidia-ctk-installer binary
119+
FROM nvcr.io/nvidia/cuda:12.8.1-base-ubi8 AS artifacts
120+
121+
COPY --from=rpmpackages /artifacts/rpm /artifacts/rpm
122+
COPY --from=debpackages /artifacts/deb /artifacts/deb
123+
COPY --from=build /artifacts/bin /artifacts/build
124+
125+
FROM nvcr.io/nvidia/cuda:12.8.1-base-ubi8
73126

74-
COPY --from=build /artifacts/nvidia-ctk-installer /work/nvidia-ctk-installer
75-
RUN ln -s nvidia-ctk-installer nvidia-toolkit
127+
ENV NVIDIA_DISABLE_REQUIRE="true"
128+
ENV NVIDIA_VISIBLE_DEVICES=void
129+
ENV NVIDIA_DRIVER_CAPABILITIES=utility
76130

131+
COPY --from=artifacts /artifacts/rpm /artifacts/rpm
132+
COPY --from=artifacts /artifacts/deb /artifacts/deb
133+
COPY --from=artifacts /artifacts/build /work
134+
135+
WORKDIR /work
77136
ENV PATH=/work:$PATH
78137

79138
ARG VERSION

deployments/container/Makefile

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,13 @@ $(IMAGE_TARGETS): image-%: $(ARTIFACTS_ROOT)
9090
--provenance=false --sbom=false \
9191
$(DOCKER_BUILD_OPTIONS) \
9292
$(DOCKER_BUILD_PLATFORM_OPTIONS) \
93+
$(INTERMEDIATE_TARGET) \
9394
--tag $(IMAGE) \
9495
--build-arg ARTIFACTS_ROOT="$(ARTIFACTS_ROOT)" \
9596
--build-arg GOLANG_VERSION="$(GOLANG_VERSION)" \
9697
--build-arg PACKAGE_DIST="$(PACKAGE_DIST)" \
98+
--build-arg PACKAGE_DIST_DEB="$(PACKAGE_DIST_DEB)" \
99+
--build-arg PACKAGE_DIST_RPM="$(PACKAGE_DIST_RPM)" \
97100
--build-arg PACKAGE_VERSION="$(PACKAGE_VERSION)" \
98101
--build-arg VERSION="$(VERSION)" \
99102
--build-arg GIT_COMMIT="$(GIT_COMMIT)" \
@@ -103,14 +106,19 @@ $(IMAGE_TARGETS): image-%: $(ARTIFACTS_ROOT)
103106
-f $(DOCKERFILE) \
104107
$(CURDIR)
105108

109+
110+
PACKAGE_DIST_DEB = ubuntu18.04
111+
# TODO: This needs to be set to centos8 for ppc64le builds
112+
PACKAGE_DIST_RPM = centos7
113+
106114
build-ubuntu%: DOCKERFILE_SUFFIX := ubuntu
107115
build-ubuntu%: PACKAGE_DIST = ubuntu18.04
108116

109117
build-ubi8: DOCKERFILE_SUFFIX := ubi8
110118
build-ubi8: PACKAGE_DIST = centos7
111119

112-
build-packaging: DOCKERFILE_SUFFIX := packaging
113-
build-packaging: PACKAGE_ARCH := amd64
120+
build-packaging: DOCKERFILE_SUFFIX := ubi8
121+
build-packaging: INTERMEDIATE_TARGET := --target=packaging
114122
build-packaging: PACKAGE_DIST = all
115123

116124
# Test targets

0 commit comments

Comments
 (0)