mattsse / chromiumoxide

Chrome Devtools Protocol rust API
Apache License 2.0
755 stars 78 forks source link

Error launching browser: No such file or directory (os error 2) on Docker #219

Closed juddbaguio closed 4 months ago

juddbaguio commented 4 months ago

I have created a REST API to do some headless chromium automation using Axum. This is the handler's logic.

#[axum::debug_handler]
async fn verify_license(
    Query(params): Query<VerifyLicenseParams>,
    State(browser_config): State<BrowserConfig>,
) -> Result<VerifyLicenseResult, AppError> {
    println!("Verifying license: {}", params.license_no);
    println!("browser config: {:?}", browser_config);
    let (mut browser, mut handler) = Browser::launch(browser_config)
        .map_err(|err| {
            println!("Error launching browser: {}", err);
            AppError(err.into())
        })
        .await?;
    println!("Browser launched");
 // ...rest of the code
}

And the way I setup my binaries, the browser config, and the router

pub async fn start_service() -> anyhow::Result<()> {
    let default_config = {
        let download_path = Path::new("./download");
        tokio::fs::create_dir_all(&download_path).await?;
        let fetcher = BrowserFetcher::new(
            BrowserFetcherOptions::builder()
                .with_path(download_path)
                .build()?,
        );
        let info = fetcher.fetch().await?;

        println!("Using browser: {}", info.executable_path.display());

        BrowserConfig::builder()
            .chrome_executable(info.executable_path)
            .build()
            .unwrap()
    };

    let app = Router::new()
        // `POST /users` goes to `create_user`
        .route("/verify-license", routing::get(verify_license))
        .with_state(default_config);

    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
    println!("Listening on http://{}", listener.local_addr()?);

    axum::serve(listener, app).await?;

    Ok(())
}

When ran locally, it's working but upon deploying it with Docker and calling the API endpoint. I receive the following logs below:

image

For context, this is the Dockerfile that I am using.

# Using the `rust-musl-builder` as base image, instead of 
# the official Rust toolchain
FROM clux/muslrust:nightly AS chef
USER root
RUN cargo +nightly install cargo-chef

WORKDIR /prc-physician-license-validator-api

FROM chef AS planner
COPY . .
RUN cargo +nightly chef prepare --recipe-path recipe.json

FROM chef AS builder
COPY --from=planner /prc-physician-license-validator-api/recipe.json recipe.json
# Notice that we are specifying the --target flag!
RUN cargo +nightly chef cook --release --target x86_64-unknown-linux-musl --recipe-path recipe.json
COPY . .
RUN cargo +nightly build --release --target x86_64-unknown-linux-musl 

FROM alpine AS runtime
USER root
WORKDIR /app
COPY --from=builder /prc-physician-license-validator-api/target/x86_64-unknown-linux-musl/release/prc-physician-license-validator-api .
EXPOSE 3000
CMD ["./prc-physician-license-validator-api"]

Edit: I used docker desktop to traverse the current working directory of the container. Based from the image below, chrome is existent. image

juddbaguio commented 4 months ago

I used the following Dockerfile instead:

# Using the `rust-musl-builder` as base image, instead of 
# the official Rust toolchain
FROM clux/muslrust:nightly AS chef
USER root
RUN cargo +nightly install cargo-chef

WORKDIR /prc-physician-license-validator-api

FROM chef AS planner
COPY . .
RUN cargo +nightly chef prepare --recipe-path recipe.json

FROM chef AS builder
COPY --from=planner /prc-physician-license-validator-api/recipe.json recipe.json
# Notice that we are specifying the --target flag!
RUN cargo +nightly chef cook --release --target x86_64-unknown-linux-musl --recipe-path recipe.json
COPY . .
RUN cargo +nightly build --release --target x86_64-unknown-linux-musl 

FROM alpine AS runtime
USER root

RUN apk upgrade --no-cache --available \
    && apk add --no-cache \
    chromium-swiftshader \
    ttf-freefont \
    font-noto-emoji \
    && apk add --no-cache \
    --repository=https://dl-cdn.alpinelinux.org/alpine/edge/community \
    font-wqy-zenhei

ENV CHROME_BIN=/usr/bin/chromium-browser \
    CHROME_PATH=/usr/lib/chromium/

WORKDIR /app
COPY --from=builder /prc-physician-license-validator-api/target/x86_64-unknown-linux-musl/release/prc-physician-license-validator-api .
EXPOSE 8080
CMD ["./prc-physician-license-validator-api"]

And updated the BrowserConfig to the following snippet:

let default_config = BrowserConfig::builder().no_sandbox().build().unwrap();