Skip to content

Commit 2ef5b3d

Browse files
authored
Merge pull request #286 from cgwalters/install-use-varlib-containers
install: Optionally use host mounted `/var/lib/containers`
2 parents ba8f744 + 807483f commit 2ef5b3d

File tree

4 files changed

+50
-42
lines changed

4 files changed

+50
-42
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -116,39 +116,13 @@ jobs:
116116
run: sudo tar -C / -xvf bootc.tar.zst
117117
- name: Integration tests
118118
run: bootc internal-tests run-container-integration
119-
build-skopeo-ubuntu:
120-
name: "Build skopeo git main for ubuntu"
121-
runs-on: ubuntu-latest
122-
steps:
123-
- uses: actions/checkout@v3
124-
with:
125-
repository: containers/skopeo
126-
path: skopeo
127-
- name: Install build deps
128-
run: |
129-
sudo sed -ie s,'# deb-src,deb-src,' /etc/apt/sources.list
130-
sudo apt update
131-
sudo apt build-dep -y skopeo
132-
- uses: actions/setup-go@v4
133-
with:
134-
go-version: '>=1.20'
135-
- name: Build skopeo
136-
run: cd skopeo && make bin/skopeo PREFIX=/usr
137-
- name: Upload binary
138-
uses: actions/upload-artifact@v4
139-
with:
140-
name: skopeo-ubuntu
141-
path: skopeo/bin/skopeo
142119
privtest-alongside:
143120
name: "Test install-alongside"
144-
needs: [build-fedora, build-skopeo-ubuntu]
121+
needs: [build-fedora]
145122
runs-on: ubuntu-latest
146123
steps:
147-
- name: Download
148-
uses: actions/download-artifact@v4
149-
with:
150-
name: skopeo-ubuntu
151-
- run: chmod a+x skopeo && sudo mv skopeo /usr/bin
124+
- name: Ensure host skopeo is disabled
125+
run: sudo rm -f /bin/skopeo /usr/bin/skopeo
152126
- name: Download
153127
uses: actions/download-artifact@v3
154128
with:
@@ -158,7 +132,7 @@ jobs:
158132
- name: Integration tests
159133
run: |
160134
set -xeuo pipefail
161-
sudo podman run --rm -ti --privileged -v /:/target -v ./usr/bin/bootc:/usr/bin/bootc --pid=host --security-opt label=disable \
135+
sudo podman run --rm -ti --privileged --env RUST_LOG=debug -v /:/target -v /var/lib/containers:/var/lib/containers -v ./usr/bin/bootc:/usr/bin/bootc --pid=host --security-opt label=disable \
162136
quay.io/centos-bootc/fedora-bootc-dev:eln bootc install to-filesystem \
163137
--karg=foo=bar --disable-selinux --replace=alongside /target
164138
ls -al /boot/loader/

docs/install.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,8 @@ inside the container.
2727
There are two sub-commands: `bootc install to-disk` and `boot install to-filesystem`.
2828

2929
However, nothing *else* (external) is required to perform a basic installation
30-
to disk. (The one exception to host requirements today is that the host must
31-
have `skopeo` installed. This is a bug; more information in
32-
[this issue](https://github.com/containers/bootc/issues/81).)
30+
to disk - the container image itself comes with a baseline self-sufficient installer
31+
that sets things up ready to boot.
3332

3433
This is motivated by experience gained from the Fedora CoreOS
3534
project where today the expectation is that one boots from a pre-existing disk
@@ -58,7 +57,7 @@ to an existing system and install your container image. Failure to run
5857
Here's an example of using `bootc install` (root/elevated permission required):
5958

6059
```bash
61-
podman run --rm --privileged --pid=host --security-opt label=type:unconfined_t <image> bootc install to-disk /path/to/disk
60+
podman run --rm --privileged --pid=host -v /var/lib/containers:/var/lib/containers --security-opt label=type:unconfined_t <image> bootc install to-disk /path/to/disk
6261
```
6362

6463
Note that while `--privileged` is used, this command will not perform any
@@ -70,6 +69,10 @@ The `--pid=host --security-opt label=type:unconfined_t` today
7069
make it more convenient for bootc to perform some privileged
7170
operations; in the future these requirement may be dropped.
7271

72+
The `-v /var/lib/containers:/var/lib/containers` option is required in order
73+
for the container to access its own underlying image, which is used by
74+
the installation process.
75+
7376
Jump to the section for [`install to-filesystem`](#more-advanced-installation) later
7477
in this document for additional information about that method.
7578

@@ -221,7 +224,7 @@ via e.g.:
221224

222225
```bash
223226
truncate -s 10G exampleos.raw
224-
podman run --rm --privileged --pid=host --security-opt label=type:unconfined_t -v .:/output <yourimage> bootc install to-disk --generic-image --via-loopback /output/myimage.raw
227+
podman run --rm --privileged --pid=host --security-opt label=type:unconfined_t -v /var/lib/containers:/var/lib/containers -v .:/output <yourimage> bootc install to-disk --generic-image --via-loopback /output/myimage.raw
225228
```
226229

227230
Notice that we use `--generic-image` for this use case.
@@ -239,7 +242,7 @@ support the root storage setup already initialized.
239242
The core command should look like this (root/elevated permission required):
240243

241244
```bash
242-
podman run --rm --privileged -v /:/target \
245+
podman run --rm --privileged -v /var/lib/containers:/var/lib/containers -v /:/target \
243246
--pid=host --security-opt label=type:unconfined_t \
244247
<image> \
245248
bootc install to-filesystem --replace=alongside /target

lib/src/install.rs

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,8 @@ pub(crate) struct SourceInfo {
246246
pub(crate) selinux: bool,
247247
/// Whether the source is available in the host mount namespace
248248
pub(crate) in_host_mountns: bool,
249+
/// Whether we were invoked with -v /var/lib/containers:/var/lib/containers
250+
pub(crate) have_host_container_storage: bool,
249251
}
250252

251253
// Shared read-only global state
@@ -388,23 +390,41 @@ impl SourceInfo {
388390
};
389391
let digest = crate::podman::imageid_to_digest(&container_info.imageid)?;
390392

393+
let root = Dir::open_ambient_dir("/", cap_std::ambient_authority())?;
394+
let have_host_container_storage = Utf8Path::new(crate::podman::CONTAINER_STORAGE)
395+
.try_exists()?
396+
&& ostree_ext::mountutil::is_mountpoint(
397+
&root,
398+
crate::podman::CONTAINER_STORAGE.trim_start_matches('/'),
399+
)?
400+
.unwrap_or_default();
401+
391402
// Verify up front we can do the fetch
392-
require_skopeo_with_containers_storage()?;
403+
if have_host_container_storage {
404+
tracing::debug!("Host container storage found");
405+
} else {
406+
tracing::debug!(
407+
"No {} mount available, checking skopeo",
408+
crate::podman::CONTAINER_STORAGE
409+
);
410+
require_skopeo_with_containers_storage()?;
411+
}
393412

394-
Self::new(imageref, Some(digest), true)
413+
Self::new(imageref, Some(digest), true, have_host_container_storage)
395414
}
396415

397416
#[context("Creating source info from a given imageref")]
398417
pub(crate) fn from_imageref(imageref: &str) -> Result<Self> {
399418
let imageref = ostree_container::ImageReference::try_from(imageref)?;
400-
Self::new(imageref, None, false)
419+
Self::new(imageref, None, false, false)
401420
}
402421

403422
/// Construct a new source information structure
404423
fn new(
405424
imageref: ostree_container::ImageReference,
406425
digest: Option<String>,
407426
in_host_mountns: bool,
427+
have_host_container_storage: bool,
408428
) -> Result<Self> {
409429
let cancellable = ostree::gio::Cancellable::NONE;
410430
let commit = Task::new("Reading ostree commit", "ostree")
@@ -425,6 +445,7 @@ impl SourceInfo {
425445
digest,
426446
selinux,
427447
in_host_mountns,
448+
have_host_container_storage,
428449
})
429450
}
430451
}
@@ -511,10 +532,16 @@ async fn initialize_ostree_root_from_self(
511532
}
512533
};
513534

514-
// We need to fetch the container image from the root mount namespace
515-
let skopeo_cmd = run_in_host_mountns("skopeo");
535+
// We need to fetch the container image from the root mount namespace. If
536+
// we don't have /var/lib/containers mounted in this image, fork off skopeo
537+
// in the host mountnfs.
538+
let skopeo_cmd = if !state.source.have_host_container_storage {
539+
Some(run_in_host_mountns("skopeo"))
540+
} else {
541+
None
542+
};
516543
let proxy_cfg = ostree_container::store::ImageProxyConfig {
517-
skopeo_cmd: Some(skopeo_cmd),
544+
skopeo_cmd,
518545
..Default::default()
519546
};
520547

lib/src/podman.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ use serde::Deserialize;
44
use crate::install::run_in_host_mountns;
55
use crate::task::Task;
66

7+
/// Where we look inside our container to find our own image
8+
/// for use with `bootc install`.
9+
pub(crate) const CONTAINER_STORAGE: &str = "/var/lib/containers";
10+
711
#[derive(Deserialize)]
812
#[serde(rename_all = "PascalCase")]
913
pub(crate) struct Inspect {

0 commit comments

Comments
 (0)