Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dockerfile refactor #153

Closed
wants to merge 37 commits into from

Conversation

allen-woods
Copy link

Fixed multiple issues with Dockerfile code blocks in docs, as follows:

  • Fixed missing leading dash for options in calls to tar.
  • curl -L makes use of wget unnecessary for binaryen.
  • curl -o for more manageable filenames in container.
  • tar -z to enable gzip extraction for all downloaded files.
  • sed -i to convert prepend of lib.rs away from cat -.
  • Reduced calls to sed by providing multiple filter clauses.
  • Increased readability.

Copy link
Member

@arctic-hen7 arctic-hen7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great to me, thanks very much! I'm not on a machine on which I can easily test these right now, and the CI unfortunately doesn't have any testing for them yet, so I assume they run on your machine (in which case they should, given it's Docker, run everywhere)?

@allen-woods
Copy link
Author

allen-woods commented Jun 19, 2022

This looks great to me, thanks very much! I'm not on a machine on which I can easily test these right now, and the CI unfortunately doesn't have any testing for them yet, so I assume they run on your machine (in which case they should, given it's Docker, run everywhere)?

There are some unforeseen problems I'm fixing to get this finalized.

  • perseus-size-opt is currently downloaded without any version supplied.
    • This breaks images based on perseus releases prior to 0.3.5.
  • wasm-bindgen chokes because the following dependencies are needed through apt -y install:
    • libssl-dev
    • openssl
    • pkg-config

Forgive me if I'm wrong, but from what I understand currently, the missing wasm-bindgen dependencies imply that all builds based on current Docker Deployment docs will fail.

Successful compilation via perseus deploy has been achieved for 0.3.5 and later using the following:

Update:The server is working!

Currently, version 0.3.3 is failing to build due to an error outside the scope of the Dockerfile.

The errors I'm seeing are related to app::get_plugins, something I am unable to locate in the source code used by the container.

@arctic-hen7
Copy link
Member

So everything is working now except for the v0.3.3 one? Could it be pulling in a .perseus/ folder from a newer version? Maybe run perseus clean just to check... If that doesn't work and you've got no other ideas then I'm happy to leave the v0.3.3 docs as they were.

@phaleth
Copy link
Contributor

phaleth commented Jun 19, 2022

I'm glad to see this moving forward! I like the changes made by @allen-woods. Been wanting to do an update PR myself, but too short on time lately.

Popping in to say there is this little gotcha that at some point, I think at version 0.3.4 the tiny example dir has moved from examples/tiny to examples/comprehensive/tiny.

Hope this is gonna be merged. I'm learning from the changes proposed. Thank you.

@allen-woods
Copy link
Author

@arctic-hen7 So everything is working now except for the v0.3.3 one?

Correct.

@arctic-hen7 Could it be pulling in a .perseus/ folder from a newer version? Maybe run perseus clean just to check... If that doesn't work and you've got no other ideas then I'm happy to leave the v0.3.3 docs as they were.

I will be testing all variations of the Dockerfile code today after I've made my adjustments to all of them, then I'll circle back to the 0.3.3 image in hopes of correcting what may be happening there.

@phaleth I'm glad to see this moving forward! I like the changes made by @allen-woods. Been wanting to do an update PR myself, but too short on time lately.

Thank you, I was hoping I wasn't stepping on any toes by doing a refactor to your work.

@phaleth Popping in to say there is this little gotcha that at some point, I think at version 0.3.4 the tiny example dir has moved from examples/tiny to examples/comprehensive/tiny.

Thanks for the catch (I found it after a couple of failed builds). The manual wee_alloc version of 0.3.5 container compiles successfully, but docker run gives me the following error:

thread 'main' panicked at 'you must provide your own error pages in production', /usr/local/cargo/registry/src/github.com-1ecc6299db9ec823/perseus-0.3.5/src/error_pages.rs:148:9

I take it this means the project requires the creation of an error page beyond what examples/comprehensive/tiny provides.

@phaleth Hope this is gonna be merged. I'm learning from the changes proposed. Thank you.

Awesome! I'm hoping I can contribute to this project going forward. I haven't had the time myself, but now I do (for a while).

@arctic-hen7
Copy link
Member

arctic-hen7 commented Jun 19, 2022

The tiny example is missing defined error pages, yes. It can work with the defaults in development, but they're disabled in production. I'll add some to it this evening!

@allen-woods
Copy link
Author

allen-woods commented Jun 19, 2022

The tiny example is missing defined error pages, yes. It can work with the defaults in development, but they're disabled in production. I'll add some to it this evening!

👍🏻 Thanks!

Edit: The problems compiling older versions can be fixed using cargo update -p and cargo update --precise.

@arctic-hen7
Copy link
Member

I think the issue might be that we need to get a specific tag of the simple example from the size optimizations plugin's repo. Right now, the Dockerfile seems to always be fetching from main, which could be leading to asymmetries in the engine structure. Pinning to a tag should fix this if I'm right.

arctic-hen7 added a commit that referenced this pull request Jun 20, 2022
@arctic-hen7
Copy link
Member

The error pages are added to the tiny example now, so deployment of that should work now. Please let me know if it doesn't!

@phaleth
Copy link
Contributor

phaleth commented Jun 20, 2022

@arctic-hen7 pinning to a tag is already in place. Currently, the codeload link grabs the v0.1.7 tag of the arctic-hen7/perseus-size-opt repo. I think the problem is that versions used in these Dockerfile examples are outdated, but even if all versions are updated to latest greatest bugs might not dissapear and new ones might come up.

https://github.com/arctic-hen7/perseus/blob/f3e3f824530d7103fe776282367e0b872ac0f921/docs/0.3.0-0.3.3/en-US/deploying/docker.md?plain=1#L44-L45

I'm with @allen-woods on the thought the specific perseus version should be able to tell which version of the perseus-size-opt plugin is required, but I have absolutely no clue how to achieve anything like that and actually, I still think that the perseus-size-opt plugin is just an extra effort. I remember once frequent updates to perseus started comming in I always rather opted out of using the perseus-size-opt plugin and used wee_alloc directly. Best of luck with all the fiddling.

@arctic-hen7
Copy link
Member

So it is, I misread that codeload line I think. @allen-woods note that Bonnie is just a command runner, it won't be crashing, it'll be the underlying commands it's running.

I think it might be best to leave the size optimizations plugin completely out of it, since I'm very likely to remove it altogether in the next version, which removes .perseus/, making it a little unnecessary. That's the simplest solution probably.

@allen-woods
Copy link
Author

Thank you @phaleth and @arctic-hen7 for both of your input during this process.

I believe I have isolated the problem that's been common across all of the failed builds.

After running cargo install perseus-cli --version <version>, the dependencies need to be locked by running cargo update with both the -p and --precise options. I figured this out when attempting to compile perseus-cli v0.3.1 and it compiled perseus v0.3.5 as a dependency. 😮

I'll get to work on this tonight and try to get v0.3.3 and at least one of the bonnie branch tests working.
This should be the "one fix to fix them all".

@allen-woods
Copy link
Author

allen-woods commented Jun 24, 2022

I am proud to announce that I have completed my work on all of the dockerfile docs.

I have personally tested this documentation and confirm that everything 'Just Works™', with the following minor caveat:

Currently, perseus-size-opt lacks support for perseus v0.4.0-beta.1 syntax, causing examples/simple in that repo to fail. Once this issue closes, none of the deployments will fail.

There are two bugs I provided patches for in the Dockerfile examples I wrote.

  • Problem 1:
    • bonnie.toml contains unescaped backtick (`) symbols that break calls to echo from bonnie, crashing container builds.
  • Proposed Solution:
    • I recommend either escaping all backticks and replacing hard quotes (') with them where appropriate, or converting all backticks to hard quotes as I chose to do out of simplicity.
  • Problem 2.
    • Starting in perseus v0.3.5, the perseus prep, or possibly the perseus tinker command generates #![allow(clippy::unused_unit)] that causes cargo to throw an error stating that "inner attributes are not allowed in this context", crashing container builds.
  • Proposed Solution:
    • I recommend removing generation of the bang (!) character in the prep or tinker code to get rid of this error.

Edit: I have tested these builds on a first generation M1 MacBook Pro, so there are no issues on M1 machines.

@arctic-hen7
Copy link
Member

Regarding the plugin support in v0.4.x, please see here. Could you show me where in bonnie.toml the unescaped backticks were?

In terms of problem 2, that's due to a longstanding wasm-bindgen issue that means useless warnings get generated without that attribute (including the !). I don't think it's causing a problem per se, it'll likely be perseus tinker that's causing the problem by inserting some stuff into .perseus/lib.rs above that attribute, rendering its position invalid. I seem to recall encountering this issue in the past and being able to deal with it very easily like so in the plugin itself:

let lib_contents_with_wee_alloc = lib_contents.replace(
        "#![allow(clippy::unused_unit)]",
        &format!("#![allow(clippy::unused_unit)]\n{}\n", WEE_ALLOC_DEF),
);

That code is still there, so I'm not sure why that would break. Also, the website is running on v0.3.5 with the plugin without problems, which means there might be something deeper going on here. Could you post the contents of .perseus/lib.rs after running perseus tinker inside the container? That should show if the plugin is misbehaving...

@allen-woods
Copy link
Author

allen-woods commented Jun 26, 2022

Regarding the plugin support in v0.4.x, please see here.

Thank you, I had no idea that was in the roadmap.

Could you show me where in bonnie.toml the unescaped backticks were?

Locations of unescaped backticks are as follows:

bonne.toml

  • Line 10
    • Col 231
    • Col 244
    • Col 247
    • Col 253
    • Col 380
    • Col 408
  • Line 18
    • Col 237
    • Col 250
    • Col 253
    • Col 259
    • Col 386
    • Col 414

In terms of problem 2, that's due to a longstanding wasm-bindgen issue that means useless warnings get generated without that attribute (including the !). I don't think it's causing a problem per se, it'll likely be perseus tinker that's causing the problem by inserting some stuff into .perseus/lib.rs above that attribute, rendering its position invalid. I seem to recall encountering this issue in the past and being able to deal with it very easily like so in the plugin itself:

let lib_contents_with_wee_alloc = lib_contents.replace(
        "#![allow(clippy::unused_unit)]",
        &format!("#![allow(clippy::unused_unit)]\n{}\n", WEE_ALLOC_DEF),
);

That code is still there, so I'm not sure why that would break. Also, the website is running on v0.3.5 with the plugin without problems, which means there might be something deeper going on here. Could you post the contents of .perseus/lib.rs after running perseus tinker inside the container? That should show if the plugin is misbehaving...

Please advise if the following data indicates the wasm-bindgen bug is related to, or will be solved by the deprecation of perseus-size-opt.

The error mesage as printed by docker buildx build ...:

#24 105.2    Compiling perseus-size-opt-example-simple v0.1.7 (/app/simple)
#24 105.2    Compiling perseus-engine v0.3.5 (/app/simple/.perseus)
#24 105.2 error: an inner attribute is not permitted in this context
#24 105.2  --> src/lib.rs:3:1
#24 105.2   |
#24 105.2 3 | #![allow(clippy::unused_unit)] // rustwasm/wasm-bindgen#2774 awaiting next `wasm-bindgen` release
#24 105.2   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#24 105.2 ...
#24 105.2 6 | pub use app::__perseus_main as main;
#24 105.2   | ------------------------------------ the inner attribute doesn't annotate this `use` import
#24 105.2   |
#24 105.2   = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
#24 105.2 help: to annotate the `use` import, change the attribute from inner to outer style
#24 105.2   |
#24 105.2 3 - #![allow(clippy::unused_unit)] // rustwasm/wasm-bindgen#2774 awaiting next `wasm-bindgen` release
#24 105.2 3 + #[allow(clippy::unused_unit)] // rustwasm/wasm-bindgen#2774 awaiting next `wasm-bindgen` release
#24 105.2   |
#24 105.2
#24 105.2 error: could not compile `perseus-engine` due to previous error
#24 105.2 Error: Compiling your crate to WebAssembly failed
#24 105.2 Caused by: failed to execute `cargo build`: exited with exit status: 101

Unabridged contents of ./.perseus/src/lib.rs within the container:

# pwd
/app/simple
# cat -n ./.perseus/src/lib.rs
     1	#[global_allocator]
     2	static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
     3	#![allow(clippy::unused_unit)] // rustwasm/wasm-bindgen#2774 awaiting next `wasm-bindgen` release
     4
     5	// The user should use the `main` macro to create this wrapper
     6	pub use app::__perseus_main as main;
     7
     8	use perseus::{
     9	    checkpoint, create_app_route,
    10	    internal::{
    11	        router::{PerseusRouter, PerseusRouterProps},
    12	        shell::get_render_cfg,
    13	    },
    14	    plugins::PluginAction,
    15	    templates::TemplateNodeType,
    16	};
    17	use sycamore::prelude::view;
    18	use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
    19
    20	/// The entrypoint into the app itself. This will be compiled to Wasm and actually executed, rendering the rest of the app.
    21	#[wasm_bindgen]
    22	pub fn run() -> Result<(), JsValue> {
    23	    let app = main();
    24	    let plugins = app.get_plugins();
    25
    26	    checkpoint("begin");
    27	    // Panics should always go to the console
    28	    std::panic::set_hook(Box::new(console_error_panic_hook::hook));
    29
    30	    plugins
    31	        .functional_actions
    32	        .client_actions
    33	        .start
    34	        .run((), plugins.get_plugin_data());
    35	    checkpoint("initial_plugins_complete");
    36
    37	    // Get the root we'll be injecting the router into
    38	    let root = web_sys::window()
    39	        .unwrap()
    40	        .document()
    41	        .unwrap()
    42	        .query_selector(&format!("#{}", app.get_root()))
    43	        .unwrap()
    44	        .unwrap();
    45
    46	    // Create the route type we'll use for this app, based on the user's app definition
    47	    create_app_route! {
    48	        name => AppRoute,
    49	        // The render configuration is injected verbatim into the HTML shell, so it certainly should be present
    50	        render_cfg => &get_render_cfg().expect("render configuration invalid or not injected"),
    51	        // TODO avoid unnecessary allocation here (major problem!)
    52	        // The `G` parameter is ambient here for `RouteVerdict`
    53	        templates => &main::<G>().get_templates_map(),
    54	        locales => &main::<G>().get_locales()
    55	    }
    56	    // Create a new version of the router with that
    57	    type PerseusRouterWithAppRoute<G> = PerseusRouter<G, AppRoute<TemplateNodeType>>;
    58
    59	    // Set up the properties we'll pass to the router
    60	    let router_props = PerseusRouterProps {
    61	        locales: app.get_locales(),
    62	        error_pages: app.get_error_pages(),
    63	    };
    64
    65	    sycamore::render_to(
    66	        move || {
    67	            view! {
    68	                // Actually render the router
    69	                // The Perseus router includes our entire app, and is, for all intents and purposes, the app itself
    70	                PerseusRouterWithAppRoute(router_props)
    71	            }
    72	        },
    73	        &root,
    74	    );
    75
    76	    Ok(())
    77	}

@arctic-hen7
Copy link
Member

Yes, I think that will all be solved by the deprecation of the size opts plugin. Usefully, those optimizations are now bundled into perseus deploy by default! (Or they will be in the next beta.)

As for those backtick issues, I'll take a look at those soon. Thanks!

@allen-woods
Copy link
Author

Yes, I think that will all be solved by the deprecation of the size opts plugin. Usefully, those optimizations are now bundled into perseus deploy by default! (Or they will be in the next beta.)

Glad to hear that.

As for those backtick issues, I'll take a look at those soon. Thanks!

Glad to be of help. 😸

I have identified a bug when building docker images using the option --platform linux/amd64. It causes the typenum crate to fail to compile due to an invalid memory reference. Not sure why, so I avoid passing that option.

As of my latest commit I have made changes to the perseus-size-opt example in the 0.3.4 docs as follows:

  • Add CARGO_NET_GIT_FETCH_WITH_CLI=true to solve intermittent issue: Killed Fetch
  • Refactor all installation processes into separate build stages that can be run in parallel.
  • Provide conditional parse_file script for fixing inner attribute error caused by clippy.
  • Reduce number of docker commands to minimize image layers.

Currently, the perseus-size-opt example for 0.3.4 is very nearly as far as I can optimize. Adding support for command-line arguments via ARG might be a nice addition, pending your feedback of course.

What may help make the deployment on Docker more user friendly is the creation of official images.

@arctic-hen7
Copy link
Member

Fantastic! Yeah, I think official images would be very helpful. Let me know when you think these are done, and I will look into publishing them to the official Docker registry!

Also, v0.4.0 is pretty stable on optimizations now I think, so if you want to do that Dockerfile as well, you're more thwn welcome to! (No pressure of you don't, of course.) The only major differences are that any optimizations go in the project root Cargo.toml, since the .perseus/ folder is gone, and size optimizations are built into the CLI. That does mean wee_alloc needs to be set up manually though. Docs for optimizations should be about done in the next section of the docs on the website for all this.

@allen-woods
Copy link
Author

allen-woods commented Jul 19, 2022

Per commit 7c87926, I have made the following changes in 0.3.4 docs:

  • Added optional docker arguments with default values.
  • Optimized network requests down to only 2 (for 0.3.5 and lower).
  • Migrated smallest example to tiny from simple.
  • Removed cargo update -p <spec> --precise <vers> due to the next item.
  • Migrated away from cargo install in favor of extracting tarball of framework codebase over curl.

I made this last change because, in practice, running the following commands are synonymous:

  • cargo install perseus-cli
  • cargo build --bin perseus --release, from the path /perseus/packages/perseus-cli

More importantly, however, this change proved necessary to unify version numbers for dependencies across the entire framework. These dependencies are as follows:

  • perseus
  • perseus-size-opt (for 0.3.5 and lower)
  • sycamore
  • sycamore-router

In certain situations, and depending on the example, deployments can fail because of incompatible versions of these dependencies. Installing binaries with cargo unfortunately involves incompatibilities that are "baked in" at the registry! 😢

This way, uniformity of semvers can be achieved, as well as allow for greater flexibility when making adjustments to an example. That said, I only anticipate needing to provide this approach for versions 0.3.5 and lower with respect to perseus-size-opt implementations specifically.

I look forward to having all versions of the docker deployment documentation completed in the very near future. I'm revising the deployed examples to better represent the framework's capabilities, so work is progressing a touch slower than expected.

@arctic-hen7
Copy link
Member

@allen-woods, it's been a while, are you still working on this? I'm happy to accept a pared back version if that's more convenient for you.

@arctic-hen7 arctic-hen7 added C-docs Category: documentation S-waiting-on-author Status: waiting on author A-deployment Area: deployment labels Dec 1, 2022
@erlend-sh
Copy link

Worth noting that Docker WASM is now a thing: https://docs.docker.com/desktop/wasm/

Perhaps a sensible next step of exploration after this PR is merged?

@arctic-hen7
Copy link
Member

@erlend-sh to my understanding, Perseus' usage of Docker right now is purely for engine-side work, where Wasm isn't really relevant right now.

That having been said, especially given the growing prevalence of server-side Wasm, I think this is an excellent idea. (It would also allow Perseus to integrate with Lunatic, a new async framework.) This would require changing every target gate in Perseus, however, to make sure the compiler understands the difference between browser-side Wasm and engine-side Wasm. A simple find and replace should achieve this though.

@arctic-hen7
Copy link
Member

@allen-woods are you likely to continue work on this any time soon, or shall I close this?

@arctic-hen7
Copy link
Member

@allen-woods I'm going to close this, it's been quite a while, but let me know if you (or anybody else!) want to pick this back up, and I'll happily reopen it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-deployment Area: deployment C-docs Category: documentation S-waiting-on-author Status: waiting on author
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants