From 2e80cf5bba81b5fa03384e8f9e656be102e6ccfd Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Wed, 4 Oct 2023 22:22:15 +1100 Subject: [PATCH] feat(rust): automated deployment to fly.io (#91) * Automated deployment to fly.io * Automatically connect to boostrap node * Allow specifying addresses to connect to on startup * Make logs a bit prettier * Fmt --- .github/workflows/deploy-rust-peer.yml | 17 ++++++++++++++ README.md | 24 +++----------------- rust-peer/Cargo.toml | 2 +- rust-peer/Dockerfile | 31 +++++++++++++++++++------- rust-peer/fly.toml | 28 +++++++++++++++++++++++ rust-peer/src/main.rs | 31 +++++++++++++++++++------- 6 files changed, 95 insertions(+), 38 deletions(-) create mode 100644 .github/workflows/deploy-rust-peer.yml create mode 100644 rust-peer/fly.toml diff --git a/.github/workflows/deploy-rust-peer.yml b/.github/workflows/deploy-rust-peer.yml new file mode 100644 index 0000000..f719735 --- /dev/null +++ b/.github/workflows/deploy-rust-peer.yml @@ -0,0 +1,17 @@ +on: + push: + branches: + - "main" + +jobs: + deploy_to_fly_io: + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./rust-peer + steps: + - uses: actions/checkout@v3 + - uses: superfly/flyctl-actions/setup-flyctl@master + - run: flyctl deploy --remote-only + env: + FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} diff --git a/README.md b/README.md index a4f3378..efe10ee 100644 --- a/README.md +++ b/README.md @@ -64,39 +64,21 @@ npm run dev ## Getting started: Rust -### 1. Start your own Rust peer - -If you are the first peer in the network, simply run: - ``` cd rust-peer cargo run ``` -However, for this repo, we have a rust server already running in the cloud, and you can add your own Rust server peer to the chat network with `cargo run` from the `rust-peer` directory. +This will automatically connect you to the bootstrap node running on [fly.io](https://fly.io). -To connect your rust peer to the rest of the network, you need to add the remote multiaddress of any peer already running as a the command line argument. - -Below we have added our already running Rust peer as the arg `remote-address`: +To explore more advanced configurations if you e.g. want to set up our own network, try: ``` -cd rust-peer -cargo run -- --remote-address=/ip4/18.195.246.16/udp/9091/quic-v1/p2p/12D3KooWSmtsbL2ukwVwf8gDoTYZHnCd7sVNNVdMnCa4MkWjLujm +cargo run -- --help ``` -This will bootstrap your peer to the rest of the network, so you will see all messages sent on the chat topic in your own peer. It needs to connect via `quic-v1` because it works with all servers. - -You should see the multiaddr of the peer once its loaded, e.g. - -``` -Listen address: "/ip4/127.0.0.1/udp/49350/webrtc/certhash/uEiAs1mQgRDVdSqMsQAuEnpMW0sSj6qc5jNvx2d0r3bQoiA/p2p/12D3KooWMzXTNGDLCKy6i6eAgJPMGCxuu7NJz33T9oC5kjByY27W -``` - - ## Getting started: Go -### 1. Start peer - ``` cd go-peer go run . diff --git a/rust-peer/Cargo.toml b/rust-peer/Cargo.toml index aef963e..91f12f2 100644 --- a/rust-peer/Cargo.toml +++ b/rust-peer/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] anyhow = "1.0" -clap = { version = "4.1.11", features = ["derive"] } +clap = { version = "4.1.11", features = ["derive", "env"] } env_logger = "0.10.0" futures = "0.3.27" futures-timer = "3.0.2" diff --git a/rust-peer/Dockerfile b/rust-peer/Dockerfile index 56dfbe6..a9ec91e 100644 --- a/rust-peer/Dockerfile +++ b/rust-peer/Dockerfile @@ -1,9 +1,24 @@ -FROM rust:1.68 as builder -WORKDIR /usr/src/universal-chat -COPY . . -RUN cargo install --path . +# syntax=docker/dockerfile:1.5-labs +FROM rust:1.72.0 as builder -FROM debian:bullseye-slim -RUN apt-get update && apt-get install && rm -rf /var/lib/apt/lists/* -COPY --from=builder /usr/local/cargo/bin/rust-libp2p-webrtc-peer /usr/local/bin/rust-libp2p-webrtc-peer -CMD ["rust-libp2p-webrtc-peer"] \ No newline at end of file +RUN rustup target add x86_64-unknown-linux-musl +RUN --mount=type=cache,target=/var/cache/apt apt-get update && apt-get install -y musl-dev musl-tools + +# Run with access to the target cache to speed up builds +WORKDIR /workspace +ADD . . +RUN --mount=type=cache,target=./target \ + --mount=type=cache,target=/usr/local/cargo/registry \ + cargo build --release --target x86_64-unknown-linux-musl + +RUN --mount=type=cache,target=./target \ + mv ./target/x86_64-unknown-linux-musl/release/rust-libp2p-webrtc-peer /usr/local/bin/rust-libp2p-webrtc-peer + +FROM alpine:3 +WORKDIR /app +COPY --from=builder /usr/local/bin/rust-libp2p-webrtc-peer /usr/bin/rust-libp2p-webrtc-peer +RUN --mount=type=cache,target=/var/cache/apk apk add bind-tools + +ENV RUST_BACKTRACE=1 + +CMD ["rust-libp2p-webrtc-peer"] diff --git a/rust-peer/fly.toml b/rust-peer/fly.toml new file mode 100644 index 0000000..44ca0bc --- /dev/null +++ b/rust-peer/fly.toml @@ -0,0 +1,28 @@ +# fly.toml app configuration file generated for universal-connectivity-rust-peer on 2023-09-24T16:20:25+10:00 +# +# See https://fly.io/docs/reference/configuration/ for information about how to use this file. +# + +app = "universal-connectivity-rust-peer" +primary_region = "syd" + +[experimental] +# Resolve the special `fly-global-services` address before starting the container, see https://fly.io/docs/app-guides/udp-and-tcp/#the-fly-global-services-address. +cmd = ["/bin/sh", "-c", "set -ex; LISTEN_ADDRESS=$(getent hosts fly-global-services | cut -d' ' -f1) && rust-libp2p-webrtc-peer"] + +[env] +EXTERNAL_ADDRESS="149.248.215.31" # TODO: Remove this in favor of an AutoNAT setup. + +[[services]] +internal_port = 9090 +protocol = "udp" + +[[services.ports]] +port = "9090" + +[[services]] +internal_port = 9091 +protocol = "udp" + +[[services.ports]] +port = "9091" diff --git a/rust-peer/src/main.rs b/rust-peer/src/main.rs index 35a7889..a01adfd 100644 --- a/rust-peer/src/main.rs +++ b/rust-peer/src/main.rs @@ -50,9 +50,16 @@ struct Opt { #[clap(long, default_value = "0.0.0.0")] listen_address: IpAddr, - /// Address of a remote peer to connect to. - #[clap(long)] - remote_address: Option, + /// If known, the external address of this node. Will be used to correctly advertise our external address across all transports. + #[clap(long, env)] + external_address: Option, + + /// Nodes to connect to on startup. Can be specified several times. + #[clap( + long, + default_value = "/dns/universal-connectivity-rust-peer.fly.dev/udp/9091/quic-v1" + )] + connect: Vec, } /// An example WebRTC peer that will accept connections @@ -85,10 +92,10 @@ async fn main() -> Result<()> { .listen_on(address_quic.clone()) .expect("listen on quic"); - if let Some(remote_address) = opt.remote_address { - swarm - .dial(remote_address) - .expect("a valid remote address to be provided"); + for addr in opt.connect { + if let Err(e) = swarm.dial(addr.clone()) { + debug!("Failed to dial {addr}: {e}"); + } } let chat_topic_hash = gossipsub::IdentTopic::new(GOSSIPSUB_CHAT_TOPIC).hash(); @@ -101,8 +108,16 @@ async fn main() -> Result<()> { match select(swarm.next(), &mut tick).await { Either::Left((event, _)) => match event.unwrap() { SwarmEvent::NewListenAddr { address, .. } => { + if let Some(external_ip) = opt.external_address { + let external_address = address + .replace(0, |_| Some(external_ip.into())) + .expect("address.len > 1 and we always return `Some`"); + + swarm.add_external_address(external_address); + } + let p2p_address = address.with(Protocol::P2p(*swarm.local_peer_id())); - info!("Listen p2p address: {p2p_address:?}"); + info!("Listening on {p2p_address}"); } SwarmEvent::ConnectionEstablished { peer_id, .. } => { info!("Connected to {peer_id}");