Coming soon
diff --git a/.github/workflows/hugo.yaml b/.github/workflows/hugo.yaml new file mode 100644 index 0000000..6d69bbf --- /dev/null +++ b/.github/workflows/hugo.yaml @@ -0,0 +1,60 @@ +# Sample workflow for building and deploying a Hugo site to GitHub Pages +name: Deploy Hugo site to Pages + +on: + # Runs on pushes targeting the default branch + push: + branches: + - main + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +# Default to bash +defaults: + run: + shell: bash + +jobs: + # Build job + build: + runs-on: ubuntu-latest + env: + HUGO_VERSION: 0.115.4 + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + submodules: recursive + fetch-depth: 0 + - name: Setup Pages + id: pages + uses: actions/configure-pages@v3 + - name: Upload artifact + uses: actions/upload-pages-artifact@v1 + with: + path: ./public + + # Deployment job + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v2 \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..de6580b --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "themes/ananke"] + path = themes/ananke + url = https://github.com/theNewDynamic/gohugo-theme-ananke.git +[submodule "themes/hermit"] + path = themes/hermit + url = https://github.com/Track3/hermit.git diff --git a/.hugo_build.lock b/.hugo_build.lock new file mode 100644 index 0000000..e69de29 diff --git a/archetypes/default.md b/archetypes/default.md new file mode 100644 index 0000000..00e77bd --- /dev/null +++ b/archetypes/default.md @@ -0,0 +1,6 @@ +--- +title: "{{ replace .Name "-" " " | title }}" +date: {{ .Date }} +draft: true +--- + diff --git a/config.toml b/config.toml new file mode 100644 index 0000000..4e60475 --- /dev/null +++ b/config.toml @@ -0,0 +1,80 @@ +baseURL = "https://example.com" +languageCode = "en-us" +defaultContentLanguage = "en" +title = "Hugo Hermit" +theme = "hermit" +# enableGitInfo = true +pygmentsCodefences = true +pygmentsUseClasses = true +# hasCJKLanguage = true # If Chinese/Japanese/Korean is your main content language, enable this to make wordCount works right. +rssLimit = 10 # Maximum number of items in the RSS feed. +copyright = "This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License." # This message is only used by the RSS template. +enableEmoji = true # Shorthand emojis in content files - https://gohugo.io/functions/emojify/ +# googleAnalytics = "UA-123-45" +# disqusShortname = "yourdiscussshortname" + +[author] + name = "John Doe" + +[blackfriday] + # hrefTargetBlank = true + # noreferrerLinks = true + # nofollowLinks = true + +[taxonomies] + tag = "tags" + # Categories are disabled by default. + +[params] + dateform = "Jan 2, 2006" + dateformShort = "Jan 2" + dateformNum = "2006-01-02" + dateformNumTime = "2006-01-02 15:04 -0700" + + # Metadata mostly used in document's head + # description = "" + # images = [""] + themeColor = "#494f5c" + + homeSubtitle = "A minimal and fast theme for Hugo." + footerCopyright = ' · CC BY-NC 4.0' + # bgImg = "" # Homepage background-image URL + + # Prefix of link to the git commit detail page. GitInfo must be enabled. + # gitUrl = "https://github.com/username/repository/commit/" + + # Toggling this option needs to rebuild SCSS, requires Hugo extended version + justifyContent = false # Set "text-align: justify" to `.content`. + + relatedPosts = false # Add a related content section to all single posts page + + code_copy_button = true # Turn on/off the code-copy-button for code-fields + + # Add custom css + # customCSS = ["css/foo.css", "css/bar.css"] + + # Social Icons + # Check https://github.com/Track3/hermit#social-icons for more info. + [[params.social]] + name = "twitter" + url = "https://twitter.com/" + + [[params.social]] + name = "instagram" + url = "https://instagram.com/" + + [[params.social]] + name = "github" + url = "https://github.com/" + +[menu] + + [[menu.main]] + name = "Posts" + url = "posts/" + weight = 10 + + [[menu.main]] + name = "About" + url = "about-hugo/" + weight = 20 diff --git a/content/about-me.md b/content/about-me.md new file mode 100644 index 0000000..a51ea33 --- /dev/null +++ b/content/about-me.md @@ -0,0 +1,6 @@ ++++ +title = "About Me" +date = "2023-10-25" ++++ + +Coming soon diff --git a/content/posts/build-rust-dockerfile.md b/content/posts/build-rust-dockerfile.md new file mode 100644 index 0000000..c4d510c --- /dev/null +++ b/content/posts/build-rust-dockerfile.md @@ -0,0 +1,108 @@ +--- +title: "Dockerfile for small Rust images (with dependency build caching)" +date: 2023-10-25T12:56:00+02:00 +draft: false +--- + +# Introduction + +After reading multiple tutorials for building docker images and optimize them, I compiled an optimized Dockerfile that can: +- Have final images that are small, in the 50MB range +- Benefit from docker caching, allowing to have build times under 10s if you don't change dependencies + +We will assume here you start with a project `my_app` you already have or have created with `cargo new`. + +# Setting up + +We use this docker file. This technique is called a multi-stage build. When docker builds with `docker build` or `docker compose build`, it creates two successive images: +- One that serve to create the binary +- One that will execute the binary without the build environment + +The second one can be minimized by removing unecessary system components that are already bundled in the produced binary. + + +```Dockerfile +## BUILDER IMAGE +FROM rust:1.73 as builder + +WORKDIR /usr/app +RUN rustup target add x86_64-unknown-linux-musl +RUN apt update && apt install -y musl-tools musl-dev +RUN update-ca-certificates + +WORKDIR /usr/app/api_gateway + +RUN adduser \ + --disabled-password \ + --gecos "" \ + --home "/nonexistent" \ + --shell "/sbin/nologin" \ + --no-create-home \ + --uid 10001 \ + userland + +COPY ./Cargo.toml ./Cargo.toml +RUN mkdir src && echo "fn main(){}" > ./src/main.rs +# Build the dependencies. This is the longest part and we don´t want +# to repeat it if there is no dependency change, +# which is why there is no copy or volume for sources at this point +RUN cargo build --target x86_64-unknown-linux-musl --release +COPY ./src ./src + +# 5. Build for release. +RUN cargo build --target x86_64-unknown-linux-musl --release +## EXECUTOR +FROM alpine +# You can include a healthcheck here, for demons and network-based services. +# For http checks, don't forget curl is not readily available on alpine + +# HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ "curl --fail http://localhost:8000/health" ] +# RUN apk add curl +RUN apk add libc6-compat + +WORKDIR /opt +COPY --from=builder /etc/passwd /etc/passwd +COPY --from=builder /etc/group /etc/group +COPY --from=builder /usr/app/my_app/target/x86_64-unknown-linux-musl/release/my_app ./ + +RUN chown userland:userland ./my_app + +CMD ["/usr/app/my_app"] +``` + +Alpine doesn't natively provide glibc or libssl. For this reason, we will need some additions in the Cargo.toml file. + +At end of file, below your dependencies, add the following section: + +```ini +[target.'cfg(all(target_env = "musl", target_pointer_width = "64"))'.dependencies.jemallocator] +version = "0.3" +``` + +You can learn more about what is jemalloc [here](https://jemalloc.net/) + +If you use things that are dependent of ssl, such as reqwest, you might also need to tweak the dependency to include `rust-tls`: + +```ini +reqwest = {version = "0.11", default-features = false, features = ["json", "rustls-tls"] } +``` +## Running + +Try to `docker build` your image. If it is successful, try to `docker run` the obtained container. It should execute your binary. + +You notice your first `docker build` was probably long, several minutes long perhaps. + +Try to modify your sources, then `docker build` again. You should notice the build to be significantly faster. + +Use `docker images` and inspect image size. Smaller images are faster to push and pull over network, they also cost less to store. + +# Conclusion + +We learned to make a multi-stage build to produce small docker images for Rust, and use the best of docker caching to avoid a costy rebuild +of dependencies at every source change. + + +## Thanks to / further reading + +- [Multi stage build for docker](https://docs.docker.com/build/building/multi-stage/) +- [Notes from cargo team on dependency caching](https://hackmd.io/@kobzol/S17NS71bh) \ No newline at end of file diff --git a/content/posts/new.md b/content/posts/new.md new file mode 100644 index 0000000..8c324b1 --- /dev/null +++ b/content/posts/new.md @@ -0,0 +1,10 @@ +--- +title: "New" +date: 2023-10-25T17:39:11+02:00 +draft: true +toc: false +images: +tags: + - untagged +--- + diff --git a/hugo.toml b/hugo.toml new file mode 100644 index 0000000..34bf1b9 --- /dev/null +++ b/hugo.toml @@ -0,0 +1,72 @@ +baseURL = "https://example.com" +languageCode = "en-us" +defaultContentLanguage = "en" +title = "Diane M's blog" +theme = "hermit" +# enableGitInfo = true +pygmentsCodefences = true +pygmentsUseClasses = true +# hasCJKLanguage = true # If Chinese/Japanese/Korean is your main content language, enable this to make wordCount works right. +rssLimit = 10 # Maximum number of items in the RSS feed. +copyright = "This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License." # This message is only used by the RSS template. +enableEmoji = true # Shorthand emojis in content files - https://gohugo.io/functions/emojify/ +# googleAnalytics = "UA-123-45" +# disqusShortname = "yourdiscussshortname" + +[author] + name = "Diane M." + +[blackfriday] + # hrefTargetBlank = true + # noreferrerLinks = true + # nofollowLinks = true + +[taxonomies] + tag = "tags" + # Categories are disabled by default. + +[params] + dateform = "Jan 2, 2006" + dateformShort = "Jan 2" + dateformNum = "2006-01-02" + dateformNumTime = "2006-01-02 15:04 -0700" + + # Metadata mostly used in document's head + # description = "" + # images = [""] + themeColor = "#494f5c" + + homeSubtitle = "Personal blog" + footerCopyright = ' · CC0 License' + # bgImg = "" # Homepage background-image URL + + # Prefix of link to the git commit detail page. GitInfo must be enabled. + # gitUrl = "https://github.com/username/repository/commit/" + + # Toggling this option needs to rebuild SCSS, requires Hugo extended version + justifyContent = false # Set "text-align: justify" to `.content`. + + relatedPosts = false # Add a related content section to all single posts page + + code_copy_button = true # Turn on/off the code-copy-button for code-fields + + # Add custom css + # customCSS = ["css/foo.css", "css/bar.css"] + + # Social Icons + # Check https://github.com/Track3/hermit#social-icons for more info. + [[params.social]] + name = "github" + url = "https://github.com/princess-entrapta" + +[menu] + + [[menu.main]] + name = "Posts" + url = "posts/" + weight = 10 + + [[menu.main]] + name = "About" + url = "about-hugo/" + weight = 20 diff --git a/public/404.html b/public/404.html new file mode 100644 index 0000000..248cc36 --- /dev/null +++ b/public/404.html @@ -0,0 +1,2 @@ +
Coming soon
Coming soon
Personal blog
After reading multiple tutorials for building docker images and optimize them, I compiled an optimized Dockerfile that can:
We will assume here you start with a project my_app
you already have or have created with cargo new
.
We use this docker file. This technique is called a multi-stage build. When docker builds with docker build
or docker compose build
, it creates two successive images:
The second one can be minimized by removing unecessary system components that are already bundled in the produced binary.
## BUILDER IMAGE
+FROM rust:1.73 as builder
+
+WORKDIR /usr/app
+RUN rustup target add x86_64-unknown-linux-musl
+RUN apt update && apt install -y musl-tools musl-dev
+RUN update-ca-certificates
+
+WORKDIR /usr/app/api_gateway
+
+RUN adduser \
+ --disabled-password \
+ --gecos "" \
+ --home "/nonexistent" \
+ --shell "/sbin/nologin" \
+ --no-create-home \
+ --uid 10001 \
+ userland
+
+COPY ./Cargo.toml ./Cargo.toml
+RUN mkdir src && echo "fn main(){}" > ./src/main.rs
+# Build the dependencies. This is the longest part and we don´t want
+# to repeat it if there is no dependency change,
+# which is why there is no copy or volume for sources at this point
+RUN cargo build --target x86_64-unknown-linux-musl --release
+COPY ./src ./src
+
+# 5. Build for release.
+RUN cargo build --target x86_64-unknown-linux-musl --release
+## EXECUTOR
+FROM alpine
+# You can include a healthcheck here, for demons and network-based services.
+# For http checks, don't forget curl is not readily available on alpine
+
+# HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ "curl --fail http://localhost:8000/health" ]
+# RUN apk add curl
+RUN apk add libc6-compat
+
+WORKDIR /opt
+COPY --from=builder /etc/passwd /etc/passwd
+COPY --from=builder /etc/group /etc/group
+COPY --from=builder /usr/app/my_app/target/x86_64-unknown-linux-musl/release/my_app ./
+
+RUN chown userland:userland ./my_app
+
+CMD ["/usr/app/my_app"]
+
Alpine doesn’t natively provide glibc or libssl. For this reason, we will need some additions in the Cargo.toml file.
At end of file, below your dependencies, add the following section:
[target.'cfg(all(target_env = "musl", target_pointer_width = "64"))'.dependencies.jemallocator]
+version = "0.3"
+
You can learn more about what is jemalloc here
If you use things that are dependent of ssl, such as reqwest, you might also need to tweak the dependency to include rust-tls
:
reqwest = {version = "0.11", default-features = false, features = ["json", "rustls-tls"] }
+
Try to docker build
your image. If it is successful, try to docker run
the obtained container. It should execute your binary.
You notice your first docker build
was probably long, several minutes long perhaps.
Try to modify your sources, then docker build
again. You should notice the build to be significantly faster.
Use docker images
and inspect image size. Smaller images are faster to push and pull over network, they also cost less to store.
We learned to make a multi-stage build to produce small docker images for Rust, and use the best of docker caching to avoid a costy rebuild +of dependencies at every source change.
After reading multiple tutorials for building docker images and optimize them, I compiled an optimized Dockerfile that can:
+We will assume here you start with a project my_app
you already have or have created with cargo new
.
We use this docker file. This technique is called a multi-stage build. When docker builds with docker build
or docker compose build
, it creates two successive images:
The second one can be minimized by removing unecessary system components that are already bundled in the produced binary.
+## BUILDER IMAGE
+FROM rust:1.73 as builder
+
+WORKDIR /usr/app
+RUN rustup target add x86_64-unknown-linux-musl
+RUN apt update && apt install -y musl-tools musl-dev
+RUN update-ca-certificates
+
+WORKDIR /usr/app/api_gateway
+
+RUN adduser \
+ --disabled-password \
+ --gecos "" \
+ --home "/nonexistent" \
+ --shell "/sbin/nologin" \
+ --no-create-home \
+ --uid 10001 \
+ userland
+
+COPY ./Cargo.toml ./Cargo.toml
+RUN mkdir src && echo "fn main(){}" > ./src/main.rs
+# Build the dependencies. This is the longest part and we don´t want
+# to repeat it if there is no dependency change,
+# which is why there is no copy or volume for sources at this point
+RUN cargo build --target x86_64-unknown-linux-musl --release
+COPY ./src ./src
+
+# 5. Build for release.
+RUN cargo build --target x86_64-unknown-linux-musl --release
+## EXECUTOR
+FROM alpine
+# You can include a healthcheck here, for demons and network-based services.
+# For http checks, don't forget curl is not readily available on alpine
+
+# HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ "curl --fail http://localhost:8000/health" ]
+# RUN apk add curl
+RUN apk add libc6-compat
+
+WORKDIR /opt
+COPY --from=builder /etc/passwd /etc/passwd
+COPY --from=builder /etc/group /etc/group
+COPY --from=builder /usr/app/my_app/target/x86_64-unknown-linux-musl/release/my_app ./
+
+RUN chown userland:userland ./my_app
+
+CMD ["/usr/app/my_app"]
+
Alpine doesn’t natively provide glibc or libssl. For this reason, we will need some additions in the Cargo.toml file.
+At end of file, below your dependencies, add the following section:
+[target.'cfg(all(target_env = "musl", target_pointer_width = "64"))'.dependencies.jemallocator]
+version = "0.3"
+
You can learn more about what is jemalloc here
+If you use things that are dependent of ssl, such as reqwest, you might also need to tweak the dependency to include rust-tls
:
reqwest = {version = "0.11", default-features = false, features = ["json", "rustls-tls"] }
+
Try to docker build
your image. If it is successful, try to docker run
the obtained container. It should execute your binary.
You notice your first docker build
was probably long, several minutes long perhaps.
Try to modify your sources, then docker build
again. You should notice the build to be significantly faster.
Use docker images
and inspect image size. Smaller images are faster to push and pull over network, they also cost less to store.
We learned to make a multi-stage build to produce small docker images for Rust, and use the best of docker caching to avoid a costy rebuild +of dependencies at every source change.
+After reading multiple tutorials for building docker images and optimize them, I compiled an optimized Dockerfile that can:
+We will assume here you start with a project my_app
you already have or have created with cargo new
.
We use this docker file. This technique is called a multi-stage build. When docker builds with docker build
or docker compose build
, it creates two successive images:
The second one can be minimized by removing unecessary system components that are already bundled in the produced binary.
+## BUILDER IMAGE
+FROM rust:1.73 as builder
+
+WORKDIR /usr/app
+RUN USER=root cargo new --bin my_app
+WORKDIR /usr/app/my_app
+
+COPY ./Cargo.toml ./Cargo.toml
+
+# Build the dependencies. This is the longest part and we don´t want to repeat it if there is no dependency change,
+# which is why there is no copy or volume for sources at this point
+RUN cargo build --release
+RUN rm src/*.rs
+COPY ./src ./src
+
+RUN rm ./target/release/deps/my_app*
+# Build the sources
+RUN cargo build --release
+## EXECUTOR
+FROM alpine
+# You can include a healthcheck here, for demons and network-based services.
+# If you do, you will need a healthcheck. For web, don't forget curl is not immediately available on alpine
+
+# HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ "curl --fail http://localhost:8000/health" ]
+# RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
+WORKDIR /usr/app
+COPY --from=builder /usr/app/my_app/target/release/my_app /usr/app/my_app
+
+RUN groupadd -g 10001 appuser && \
+ useradd -u 10000 -g appuser appuser \
+ && chown -R appuser:appuser /usr/app
+
+USER appuser:appuser
+
+CMD ["/usr/app/my_app"]
+
In order for it to work on alpine, that don’t come with glibc, we will need an addition in the Cargo.toml file to use a custom memory allocator.
+At end of file, below your dependencies, add the following section:
+[target.'cfg(all(target_env = "musl", target_pointer_width = "64"))'.dependencies.jemallocator]
+version = "0.3"
+
If you use things that are dependent of openssl, such as reqwest, you might also need to tweak the dependency to include rust-tls
:
reqwest = {version = "0.11", default-features = false, features = ["json", "rustls-tls"] }
+
Try to docker build
your image. If it is successful, try to docker run
the obtained container. It should execute your binary.
You notice your first docker build
was probably long, several minutes long perhaps.
Try to modify your sources, then docker build
again. You should notice the build to be significantly faster.
Use docker images
and inspect image size. Smaller images are faster to push and pull over network, they also cost less to store.
We learned to make a multi-stage build to produce small docker images for Rust, and use the best of docker caching to avoid a costy rebuild +of dependencies at every source change.
+