feat: add ability to run an exposed container

This commit is contained in:
kjuulh 2025-07-11 21:21:12 +02:00
parent 17fcd053ac
commit 56df0f204b
4 changed files with 52 additions and 6 deletions

12
NETWORKING.md Normal file
View File

@ -0,0 +1,12 @@
# Networking
We've got multiple hosts potentially in play, and multiple containers that wants
to expose themselves on the primary host, but only 1 process can take a tcp port
on the same host at a time.
1. The primary instance, will bind to common tcp ports as required (80, 443) can
be changed.
1. TODO: TLS termination
1. Will send traffic to peers hosting their versions of a url.
1. On the peers, each container will bind to a port (TBD), maybe we will do some
long running connections instead. SOCK protocol

View File

@ -1,5 +1,6 @@
use crate::{
container_runtime::ContainerRuntimeState, grpc_client::GrpcClientState, state::ClientState,
container_runtime::ContainerRuntimeState, grpc_client::GrpcClientState, models::port::Port,
state::ClientState,
};
#[derive(clap::Parser)]
@ -22,6 +23,10 @@ impl SubscribeCommand {
.ensure_running(
&project.name,
&format!("{}:{}", project.image, project.version),
vec![Port {
host_port: 38080,
container_port: 80,
}],
)
.await?;
}

View File

@ -5,13 +5,13 @@ use bollard::{
image::CreateImageOptions,
query_parameters::{
CreateContainerOptionsBuilder, CreateImageOptionsBuilder, ListContainersOptionsBuilder,
StartContainerOptions,
StartContainerOptions, StartContainerOptionsBuilder,
},
secret::ContainerCreateBody,
secret::{ContainerCreateBody, HostConfig, PortBinding},
};
use futures_util::TryStreamExt;
use crate::state::ClientState;
use crate::{models::port::Port, state::ClientState};
#[derive(Clone)]
pub struct ContainerRuntime {
@ -20,7 +20,12 @@ pub struct ContainerRuntime {
impl ContainerRuntime {
#[tracing::instrument(skip(self), level = "trace")]
pub async fn ensure_running(&self, name: &str, image: &str) -> anyhow::Result<()> {
pub async fn ensure_running(
&self,
name: &str,
image: &str,
ports: Vec<Port>,
) -> anyhow::Result<()> {
tracing::debug!("ensuring that image is running");
let containers = self
@ -50,18 +55,34 @@ impl ContainerRuntime {
.try_collect::<Vec<_>>()
.await?;
let ports: HashMap<_, _> = ports
.iter()
.map(|p| {
(
format!("{}/tcp", p.container_port),
Some(vec![PortBinding {
host_ip: Some("0.0.0.0".into()),
host_port: Some(p.host_port.to_string()),
}]),
)
})
.collect();
self.client
.create_container(
Some(CreateContainerOptionsBuilder::new().name(name).build()),
ContainerCreateBody {
image: Some(image.into()),
host_config: Some(HostConfig {
port_bindings: Some(ports),
..Default::default()
}),
..Default::default()
},
)
.await?;
self.client
.start_container(name, None::<StartContainerOptions>)
.start_container(name, Some(StartContainerOptionsBuilder::default().build()))
.await?;
Ok(())

View File

@ -1,2 +1,10 @@
pub mod project_tag;
pub use project_tag::*;
pub mod port {
#[derive(Clone, Debug, PartialEq)]
pub struct Port {
pub host_port: usize,
pub container_port: usize,
}
}