Merge pull request #99 from emk/sqlx

Add support for static linking of `sqlx`
This commit is contained in:
Eric Kidd 2020-09-04 08:48:22 -04:00 committed by GitHub
commit 8b9a2d2e3e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 1440 additions and 23 deletions

47
CHANGELOG.md Normal file
View file

@ -0,0 +1,47 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). We do not use Semantic Versioning, because our images are tagged based on Rust releases. However, we try to maintain as much backwards compatibility as possible.
For maximum stablity, use images with tags like `ekidd/rust-musl-builder:1.46.0` or `ekidd/rust-musl-builder:nightly-2020-08-26`. These may occasionally be rebuilt, but only while they're "current", or possibly if they're recent and serious security are discovered in a library.
## 2020-09-04
### Added
- Added `examples/using-sqlx`.
### Changed
- Our OpenSSL configuration now uses environment variables prefixed with `X86_64_UNKNOWN_LINUX_MUSL_`. See [sfackler/rust-openssl#1337](https://github.com/sfackler/rust-openssl/issues/1337) and [launchbadge/sqlx#670](https://github.com/launchbadge/sqlx/issues/670) for background. This allows us to support static builds of `sqlx`, but it may break very old versions of `openssl-sys` (which were probably already broken when OpenSSL 1.0 reached its end-of-life).
## 2020-08-27
### Updated
- Update to `cargo deny` 0.7.3.
- Update to PostgreSQL 11.9.
## 2020-07-16
### Updated
- Update to `mdbook` version 0.4.1.
- Update to `cargo deny` 0.7.0.
## 2020-06-05
### Changed
- Previously, `stable` included OpenSSL 1.0.2, and `stable-openssl11` included OpenSSL 1.1.1. However, OpenSSL 1.0.2 is **no longer receiving security fixes,** so the new tagging system will be:
- `stable`: OpenSSL 1.1.1 and the latest stable Rust.
- **DEPRECATED** `stable-openssl11`: OpenSSL 1.1 and Rust 1.42.0. This will no longer be updated. Use `stable` instead.
- **DEPRECATED** `1.42.0-openssl10` and `nightly-2020-03-12-openssl10`: OpenSSL 1.0.2. These will not be updated to newer Rust. You will still be able to build newer OpenSSL 1.0.2 images manually.
I hate to break compatibility with projects that require OpenSSL 1.0.2, but since it will receive no future security updates, I no longer feel comfortable supplying pre-built images.
### Updated
- Update to `cargo deny` 0.6.7.
- Update to PostgreSQL 11.8.

View file

@ -67,7 +67,7 @@ RUN apt-get update && \
curl -fLO https://github.com/EmbarkStudios/cargo-deny/releases/download/$CARGO_DENY_VERSION/cargo-deny-$CARGO_DENY_VERSION-x86_64-unknown-linux-musl.tar.gz && \ curl -fLO https://github.com/EmbarkStudios/cargo-deny/releases/download/$CARGO_DENY_VERSION/cargo-deny-$CARGO_DENY_VERSION-x86_64-unknown-linux-musl.tar.gz && \
tar xf cargo-deny-$CARGO_DENY_VERSION-x86_64-unknown-linux-musl.tar.gz && \ tar xf cargo-deny-$CARGO_DENY_VERSION-x86_64-unknown-linux-musl.tar.gz && \
mv cargo-deny-$CARGO_DENY_VERSION-x86_64-unknown-linux-musl/cargo-deny /usr/local/bin/ && \ mv cargo-deny-$CARGO_DENY_VERSION-x86_64-unknown-linux-musl/cargo-deny /usr/local/bin/ && \
rm -rf cargo-deny-$CARGO_DENY_VERSION-x86_64-unknown-linux-musl cargo-deny-$CARGO_DENY_VERSION-x86_64-unknown-linux-musl.tar.gz rm -rf cargo-deny-$CARGO_DENY_VERSION-x86_64-unknown-linux-musl cargo-deny-$CARGO_DENY_VERSION-x86_64-unknown-linux-musl.tar.gz
# Static linking for C++ code # Static linking for C++ code
RUN sudo ln -s "/usr/bin/g++" "/usr/bin/musl-g++" RUN sudo ln -s "/usr/bin/g++" "/usr/bin/musl-g++"
@ -142,11 +142,8 @@ RUN echo "Building libpq" && \
cd ../../bin/pg_config && make && sudo make install && \ cd ../../bin/pg_config && make && sudo make install && \
rm -r /tmp/* rm -r /tmp/*
ENV OPENSSL_DIR=/usr/local/musl/ \ ENV X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_DIR=/usr/local/musl/ \
OPENSSL_INCLUDE_DIR=/usr/local/musl/include/ \ X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_STATIC=1 \
DEP_OPENSSL_INCLUDE=/usr/local/musl/include/ \
OPENSSL_LIB_DIR=/usr/local/musl/lib/ \
OPENSSL_STATIC=1 \
PQ_LIB_STATIC_X86_64_UNKNOWN_LINUX_MUSL=1 \ PQ_LIB_STATIC_X86_64_UNKNOWN_LINUX_MUSL=1 \
PG_CONFIG_X86_64_UNKNOWN_LINUX_GNU=/usr/bin/pg_config \ PG_CONFIG_X86_64_UNKNOWN_LINUX_GNU=/usr/bin/pg_config \
PKG_CONFIG_ALLOW_CROSS=true \ PKG_CONFIG_ALLOW_CROSS=true \

View file

@ -2,9 +2,16 @@
[![Docker Image](https://img.shields.io/docker/pulls/ekidd/rust-musl-builder.svg?maxAge=2592000)](https://hub.docker.com/r/ekidd/rust-musl-builder/) [![Docker Image](https://img.shields.io/docker/pulls/ekidd/rust-musl-builder.svg?maxAge=2592000)](https://hub.docker.com/r/ekidd/rust-musl-builder/)
- [Source on GitHub](https://github.com/emk/rust-musl-builder)
- [Changelog](https://github.com/emk/rust-musl-builder/blob/master/CHANGELOG.md)
**UPDATED:** The OpenSSL configuration has changed to support `sqlx`. This may break very old versions of the `openssl` crate. If this affects you, please file an issue. See the [Changelog](https://github.com/emk/rust-musl-builder/blob/master/CHANGELOG.md) for details.
## What is this? ## What is this?
Do you want to compile a completely static Rust binary with no external dependencies? If so, try: This image allows you to build static Rust binaries using `diesel`, `sqlx` or `openssl`. These images can be distributed as single executable files with no dependencies, and they should work on any modern Linux system.
To try it, run:
```sh ```sh
alias rust-musl-builder='docker run --rm -it -v "$(pwd)":/home/rust/src ekidd/rust-musl-builder' alias rust-musl-builder='docker run --rm -it -v "$(pwd)":/home/rust/src ekidd/rust-musl-builder'
@ -13,7 +20,7 @@ rust-musl-builder cargo build --release
This command assumes that `$(pwd)` is readable and writable by uid 1000, gid 1000. At the moment, it doesn't attempt to cache libraries between builds, so this is best reserved for making final release builds. This command assumes that `$(pwd)` is readable and writable by uid 1000, gid 1000. At the moment, it doesn't attempt to cache libraries between builds, so this is best reserved for making final release builds.
For a more realistic example, see the `Dockerfile` for [examples/using-diesel](./examples/using-diesel). For a more realistic example, see the `Dockerfile`s for [examples/using-diesel](./examples/using-diesel) and [examples/using-sqlx](./examples/using-sqlx).
## Deploying your Rust application ## Deploying your Rust application
@ -36,20 +43,10 @@ In general, we provide the following tagged Docker images:
Rust, please file an issue. Rust, please file an issue.
At a minimum, each of these images should be able to At a minimum, each of these images should be able to
compile [examples/using-diesel](./examples/using-diesel). compile [examples/using-diesel](./examples/using-diesel) and [examples/using-sqlx](./examples/using-sqlx).
[comp]: https://rust-lang.github.io/rustup-components-history/index.html [comp]: https://rust-lang.github.io/rustup-components-history/index.html
### OpenSSL security note
Previously, `stable` included OpenSSL 1.0.2, and `stable-openssl11` included OpenSSL 1.1.1. However, OpenSSL 1.0.2 is **no longer receiving security fixes,** so the new tagging system will be:
- `stable`: OpenSSL 1.1.1 and the latest stable Rust.
- **DEPRECATED** `stable-openssl11`: OpenSSL 1.1 and Rust 1.42.0. This will no longer be updated. Use `stable` instead.
- **DEPRECATED** `1.42.0-openssl10` and `nightly-2020-03-12-openssl10`: OpenSSL 1.0.2. These will not be updated to newer Rust. You will still be able to build newer OpenSSL 1.0.2 images manually.
I hate to break compatibility with projects that require OpenSSL 1.0.2, but since it will receive no future security updates, I no longer feel comfortable supplying pre-built images.
## Caching builds ## Caching builds
You may be able to speed up build performance by adding the following `-v` commands to the `rust-musl-builder` alias: You may be able to speed up build performance by adding the following `-v` commands to the `rust-musl-builder` alias:
@ -94,8 +91,6 @@ This image also supports the following extra goodies:
If your application uses OpenSSL, you will also need to take a few extra steps to make sure that it can find OpenSSL's list of trusted certificates, which is stored in different locations on different Linux distributions. You can do this using [`openssl-probe`](https://crates.io/crates/openssl-probe) as follows: If your application uses OpenSSL, you will also need to take a few extra steps to make sure that it can find OpenSSL's list of trusted certificates, which is stored in different locations on different Linux distributions. You can do this using [`openssl-probe`](https://crates.io/crates/openssl-probe) as follows:
```rust ```rust
extern crate openssl_probe;
fn main() { fn main() {
openssl_probe::init_ssl_cert_env_vars(); openssl_probe::init_ssl_cert_env_vars();
//... your code //... your code
@ -205,7 +200,7 @@ This is missing many of the libraries used by the `x86_64` build, and it should
## Development notes ## Development notes
After modifying the image, run `./test-image` to make sure that everything works.xs After modifying the image, run `./test-image` to make sure that everything works.
## Other ways to build portable Rust binaries ## Other ways to build portable Rust binaries

View file

@ -9,3 +9,4 @@ diesel = { version = "1", features = ["postgres", "sqlite"] }
libsqlite3-sys = { version = "*", features = ["bundled"] } libsqlite3-sys = { version = "*", features = ["bundled"] }
# Needed for Postgres. # Needed for Postgres.
openssl = "*" openssl = "*"
openssl-probe = "0.1.2"

View file

@ -46,6 +46,8 @@ where
} }
fn main() { fn main() {
openssl_probe::init_ssl_cert_env_vars();
println!("Hello, world!"); println!("Hello, world!");
// Only run our database example if we have a database. Otherwise, we just // Only run our database example if we have a database. Otherwise, we just

View file

@ -0,0 +1 @@
target

1265
examples/using-sqlx/Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,12 @@
[package]
name = "using-sqlx"
version = "0.1.0"
authors = ["Eric Kidd <git@randomhacks.net>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
openssl-probe = "0.1.2"
sqlx = { version = "0.4.0-beta.1", default-features = false, features = ["runtime-tokio", "macros", "offline", "postgres"] }
tokio = { version = "0.2", features = ["macros"] }

View file

@ -0,0 +1,25 @@
# -*- mode: dockerfile -*-
#
# An example Dockerfile showing how to build a Rust executable using this
# image, and deploy it with a tiny Alpine Linux container.
# You can override this `--build-arg BASE_IMAGE=...` to use different
# version of Rust or OpenSSL.
ARG BASE_IMAGE=ekidd/rust-musl-builder:latest
# Our first FROM statement declares the build environment.
FROM ${BASE_IMAGE} AS builder
# Add our source code.
ADD --chown=rust:rust . ./
# Build our application.
RUN cargo build --release
# Now, we need to build our _real_ Docker container, copying in `using-sqlx`.
FROM alpine:latest
RUN apk --no-cache add ca-certificates
COPY --from=builder \
/home/rust/src/target/x86_64-unknown-linux-musl/release/using-sqlx \
/usr/local/bin/
CMD /usr/local/bin/using-sqlx

View file

@ -0,0 +1,12 @@
version: "2.0"
services:
app:
build: .
volumes:
- cargo:/home/rust/.cargo
- target:/home/rust/src/target
volumes:
cargo: {}
target: {}

View file

@ -0,0 +1,23 @@
{
"db": "PostgreSQL",
"bf54a84704792059fc3a494889dce274bb09f5cadc8c7be61a9b85abbceb001f": {
"query": "SELECT $1::INTEGER AS value",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "value",
"type_info": "Int4"
}
],
"parameters": {
"Left": [
"Int4"
]
},
"nullable": [
null
]
}
}
}

View file

@ -0,0 +1,23 @@
use std::env;
use sqlx::{Connection, postgres::PgConnection};
#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
openssl_probe::init_ssl_cert_env_vars();
let url = env::var("POSTGRES_URL")
.unwrap_or_else(|_| "postgresql://postgres@localhost/postgres".to_owned());
// Create a connection.
let mut conn = PgConnection::connect(&url).await?;
// Make a simple query using the `query!` macro.
let row = sqlx::query!("SELECT $1::INTEGER AS value", 2i32)
.fetch_one(&mut conn)
.await?;
assert_eq!(row.value, Some(2));
Ok(())
}

View file

@ -4,7 +4,7 @@
set -euo pipefail set -euo pipefail
# Make sure we can build some of our more important test images. # Make sure we can build some of our more important test images.
for EXAMPLE in using-diesel; do for EXAMPLE in using-diesel using-sqlx; do
docker build \ docker build \
--build-arg BASE_IMAGE="$IMAGE_NAME" \ --build-arg BASE_IMAGE="$IMAGE_NAME" \
-t rust-musl-builder-"$EXAMPLE" \ -t rust-musl-builder-"$EXAMPLE" \

View file

@ -41,6 +41,20 @@ fi
echo -e '[PASS] ARMhf binary is statically linked.\n' echo -e '[PASS] ARMhf binary is statically linked.\n'
" "
# Make sure we can build a static executable using `sqlx`.
docker build -t rust-musl-builder-using-sqlx examples/using-sqlx
docker run --rm rust-musl-builder-using-sqlx sh -c "
set -euo pipefail
echo -e '--- Test case for sqlx:'
echo 'ldd says:'
if ldd /usr/local/bin/using-sqlx; then
echo '[FAIL] Executable is not static!' 1>&2
exit 1
fi
echo -e '[PASS] using-sqlx binary is statically linked.\n'
"
# Make sure we can build a static executable using `git2`. # Make sure we can build a static executable using `git2`.
docker build -t rust-musl-builder-linking-with-git2 examples/linking-with-git2 docker build -t rust-musl-builder-linking-with-git2 examples/linking-with-git2
docker run --rm rust-musl-builder-linking-with-git2 bash -c " docker run --rm rust-musl-builder-linking-with-git2 bash -c "