mirror of
https://github.com/deuxfleurs-org/garage.git
synced 2026-08-16 16:58:19 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0d8cb29780 | |||
| 2197753dfd | |||
| 3f95a0f717 | |||
| 7291747a28 | |||
| d104ae8711 | |||
| 194e8be1bb | |||
| 69bcc813de | |||
| ea7a571d88 | |||
| 1778e4b318 | |||
| af2b2f26b4 | |||
| a3758dc4c4 | |||
| e89f880694 | |||
| fc85508648 | |||
| 782630fc27 |
+12
-1
@@ -245,6 +245,17 @@ node:
|
|||||||
nix-daemon: 1
|
nix-daemon: 1
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
- name: multiarch-docker
|
||||||
|
image: nixpkgs/nix:nixos-22.05
|
||||||
|
environment:
|
||||||
|
DOCKER_AUTH:
|
||||||
|
from_secret: docker_auth
|
||||||
|
HOME: "/root"
|
||||||
|
commands:
|
||||||
|
- mkdir -p /root/.docker
|
||||||
|
- echo $DOCKER_AUTH > /root/.docker/config.json
|
||||||
|
- export CONTAINER_TAG=${DRONE_TAG:-$DRONE_COMMIT}
|
||||||
|
- nix-shell --attr release --run "multiarch_docker"
|
||||||
- name: refresh-index
|
- name: refresh-index
|
||||||
image: nixpkgs/nix:nixos-22.05
|
image: nixpkgs/nix:nixos-22.05
|
||||||
environment:
|
environment:
|
||||||
@@ -269,6 +280,6 @@ trigger:
|
|||||||
|
|
||||||
---
|
---
|
||||||
kind: signature
|
kind: signature
|
||||||
hmac: 362639b4c9541ad9bd06ff7f72b5235b2b0216bcb16eececd25285b6fe94ba6f
|
hmac: 103a04785c98f5376a63ce22865c2576963019bbc4d828f200d2a470a3c821ea
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -15,18 +15,24 @@ Garage [,
|
||||||
|
an experimental small-scale self hosted service provider,
|
||||||
|
which has been using it in production since its first release in 2020.
|
||||||
|
|
||||||
- Extremely high performance
|
Learn more on our dedicated documentation pages:
|
||||||
- Complete implementation of the S3 API
|
|
||||||
- Erasure coding (our replication model is simply to copy the data as is on several nodes, in different datacenters if possible)
|
|
||||||
|
|
||||||
Our main use case is to provide a distributed storage layer for small-scale self hosted services such as [Deuxfleurs](https://deuxfleurs.fr).
|
- [Goals and use cases](https://garagehq.deuxfleurs.fr/documentation/design/goals/)
|
||||||
|
- [Features](https://garagehq.deuxfleurs.fr/documentation/reference-manual/features/)
|
||||||
|
- [Quick start](https://garagehq.deuxfleurs.fr/documentation/quick-start/)
|
||||||
|
|
||||||
|
Garage is entirely free software released under the terms of the AGPLv3.
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ let
|
|||||||
name ="garage-tests";
|
name ="garage-tests";
|
||||||
paths = builtins.map (key: rustPkgs.workspace.${key} { compileMode = "test"; }) (builtins.attrNames rustPkgs.workspace);
|
paths = builtins.map (key: rustPkgs.workspace.${key} { compileMode = "test"; }) (builtins.attrNames rustPkgs.workspace);
|
||||||
});
|
});
|
||||||
|
build_convert_db = (target: (compile { inherit target git_version; release = true; }).workspace.garage_db { compileMode = "build"; });
|
||||||
|
|
||||||
in {
|
in {
|
||||||
pkgs = {
|
pkgs = {
|
||||||
@@ -23,6 +24,12 @@ in {
|
|||||||
i386 = build_debug_and_release "i686-unknown-linux-musl";
|
i386 = build_debug_and_release "i686-unknown-linux-musl";
|
||||||
arm64 = build_debug_and_release "aarch64-unknown-linux-musl";
|
arm64 = build_debug_and_release "aarch64-unknown-linux-musl";
|
||||||
arm = build_debug_and_release "armv6l-unknown-linux-musleabihf";
|
arm = build_debug_and_release "armv6l-unknown-linux-musleabihf";
|
||||||
|
convert_db = {
|
||||||
|
amd64 = build_convert_db "x86_64-unknown-linux-musl";
|
||||||
|
i386 = build_convert_db "i686-unknown-linux-musl";
|
||||||
|
arm64 = build_convert_db "aarch64-unknown-linux-musl";
|
||||||
|
arm = build_convert_db "armv6l-unknown-linux-musleabihf";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
test = {
|
test = {
|
||||||
amd64 = test (compile { inherit git_version; target = "x86_64-unknown-linux-musl"; });
|
amd64 = test (compile { inherit git_version; target = "x86_64-unknown-linux-musl"; });
|
||||||
|
|||||||
@@ -51,15 +51,15 @@ to store 2 TB of data in total.
|
|||||||
|
|
||||||
## Get a Docker image
|
## Get a Docker image
|
||||||
|
|
||||||
Our docker image is currently named `dxflrs/amd64_garage` and is stored on the [Docker Hub](https://hub.docker.com/r/dxflrs/amd64_garage/tags?page=1&ordering=last_updated).
|
Our docker image is currently named `dxflrs/garage` and is stored on the [Docker Hub](https://hub.docker.com/r/dxflrs/garage/tags?page=1&ordering=last_updated).
|
||||||
We encourage you to use a fixed tag (eg. `v0.4.0`) and not the `latest` tag.
|
We encourage you to use a fixed tag (eg. `v0.8.0`) and not the `latest` tag.
|
||||||
For this example, we will use the latest published version at the time of the writing which is `v0.4.0` but it's up to you
|
For this example, we will use the latest published version at the time of the writing which is `v0.8.0` but it's up to you
|
||||||
to check [the most recent versions on the Docker Hub](https://hub.docker.com/r/dxflrs/amd64_garage/tags?page=1&ordering=last_updated).
|
to check [the most recent versions on the Docker Hub](https://hub.docker.com/r/dxflrs/garage/tags?page=1&ordering=last_updated).
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```
|
```
|
||||||
sudo docker pull dxflrs/amd64_garage:v0.4.0
|
sudo docker pull dxflrs/garage:v0.8.0
|
||||||
```
|
```
|
||||||
|
|
||||||
## Deploying and configuring Garage
|
## Deploying and configuring Garage
|
||||||
@@ -125,7 +125,7 @@ docker run \
|
|||||||
-v /etc/garage.toml:/etc/garage.toml \
|
-v /etc/garage.toml:/etc/garage.toml \
|
||||||
-v /var/lib/garage/meta:/var/lib/garage/meta \
|
-v /var/lib/garage/meta:/var/lib/garage/meta \
|
||||||
-v /var/lib/garage/data:/var/lib/garage/data \
|
-v /var/lib/garage/data:/var/lib/garage/data \
|
||||||
lxpz/garage_amd64:v0.4.0
|
dxflrs/garage:v0.8.0
|
||||||
```
|
```
|
||||||
|
|
||||||
It should be restarted automatically at each reboot.
|
It should be restarted automatically at each reboot.
|
||||||
|
|||||||
@@ -14,10 +14,10 @@ website.
|
|||||||
|
|
||||||
Garage is an opinionated object storage solutoin, we focus on the following **desirable properties**:
|
Garage is an opinionated object storage solutoin, we focus on the following **desirable properties**:
|
||||||
|
|
||||||
|
- **Internet enabled**: made for multi-sites (eg. datacenters, offices, households, etc.) interconnected through regular Internet connections.
|
||||||
- **Self-contained & lightweight**: works everywhere and integrates well in existing environments to target [hyperconverged infrastructures](https://en.wikipedia.org/wiki/Hyper-converged_infrastructure).
|
- **Self-contained & lightweight**: works everywhere and integrates well in existing environments to target [hyperconverged infrastructures](https://en.wikipedia.org/wiki/Hyper-converged_infrastructure).
|
||||||
- **Highly resilient**: highly resilient to network failures, network latency, disk failures, sysadmin failures.
|
- **Highly resilient**: highly resilient to network failures, network latency, disk failures, sysadmin failures.
|
||||||
- **Simple**: simple to understand, simple to operate, simple to debug.
|
- **Simple**: simple to understand, simple to operate, simple to debug.
|
||||||
- **Internet enabled**: made for multi-sites (eg. datacenters, offices, households, etc.) interconnected through regular Internet connections.
|
|
||||||
|
|
||||||
We also noted that the pursuit of some other goals are detrimental to our initial goals.
|
We also noted that the pursuit of some other goals are detrimental to our initial goals.
|
||||||
The following has been identified as **non-goals** (if these points matter to you, you should not use Garage):
|
The following has been identified as **non-goals** (if these points matter to you, you should not use Garage):
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ The migration steps are as follows:
|
|||||||
1. Do `garage repair --all-nodes --yes tables` and `garage repair --all-nodes --yes blocks`,
|
1. Do `garage repair --all-nodes --yes tables` and `garage repair --all-nodes --yes blocks`,
|
||||||
check the logs and check that all data seems to be synced correctly between
|
check the logs and check that all data seems to be synced correctly between
|
||||||
nodes. If you have time, do additional checks (`scrub`, `block_refs`, etc.)
|
nodes. If you have time, do additional checks (`scrub`, `block_refs`, etc.)
|
||||||
2. Disable api and web access. Garage does not support disabling
|
2. Disable API and web access. Garage does not support disabling
|
||||||
these endpoints but you can change the port number or stop your reverse
|
these endpoints but you can change the port number or stop your reverse
|
||||||
proxy for instance.
|
proxy for instance.
|
||||||
3. Check once again that your cluster is healty. Run again `garage repair --all-nodes --yes tables` which is quick.
|
3. Check once again that your cluster is healty. Run again `garage repair --all-nodes --yes tables` which is quick.
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
+++
|
||||||
|
title = "Migrating from 0.7 to 0.8"
|
||||||
|
weight = 13
|
||||||
|
+++
|
||||||
|
|
||||||
|
**This guide explains how to migrate to 0.8 if you have an existing 0.7 cluster.
|
||||||
|
We don't recommend trying to migrate to 0.8 directly from 0.6 or older.**
|
||||||
|
|
||||||
|
**We make no guarantee that this migration will work perfectly:
|
||||||
|
back up all your data before attempting it!**
|
||||||
|
|
||||||
|
Garage v0.8 introduces new data tables that allow the counting of objects in buckets in order to implement bucket quotas.
|
||||||
|
A manual migration step is required to first count objects in Garage buckets and populate these tables with accurate data.
|
||||||
|
|
||||||
|
The migration steps are as follows:
|
||||||
|
|
||||||
|
1. Disable API and web access. Garage v0.7 does not support disabling
|
||||||
|
these endpoints but you can change the port number or stop your reverse proxy for instance.
|
||||||
|
2. Do `garage repair --all-nodes --yes tables` and `garage repair --all-nodes --yes blocks`,
|
||||||
|
check the logs and check that all data seems to be synced correctly between
|
||||||
|
nodes. If you have time, do additional checks (`scrub`, `block_refs`, etc.)
|
||||||
|
3. Check that queues are empty: run `garage stats` to query them or inspect metrics in the Grafana dashboard.
|
||||||
|
4. Turn off Garage v0.7
|
||||||
|
5. **Backup the metadata folder of all your nodes!** For instance, use the following command
|
||||||
|
if your metadata directory is `/var/lib/garage/meta`: `cd /var/lib/garage ; tar -acf meta-v0.7.tar.zst meta/`
|
||||||
|
6. Install Garage v0.8
|
||||||
|
7. **Before starting Garage v0.8**, run the offline migration step: `garage offline-repair --yes object_counters`.
|
||||||
|
This can take a while to run, depending on the number of objects stored in your cluster.
|
||||||
|
8. Turn on Garage v0.8
|
||||||
|
9. Do `garage repair --all-nodes --yes tables` and `garage repair --all-nodes --yes blocks`.
|
||||||
|
Wait for a full table sync to run.
|
||||||
|
10. Your upgraded cluster should be in a working state. Re-enable API and Web
|
||||||
|
access and check that everything went well.
|
||||||
|
11. Monitor your cluster in the next hours to see if it works well under your production load, report any issue.
|
||||||
+6
-3
@@ -137,8 +137,8 @@ let
|
|||||||
/* [2] */ hardeningDisable = [ "pie" ];
|
/* [2] */ hardeningDisable = [ "pie" ];
|
||||||
};
|
};
|
||||||
overrideArgs = old: {
|
overrideArgs = old: {
|
||||||
/* [4] */ features = [ "bundled-libs" "sled" ]
|
/* [4] */ features = [ "bundled-libs" "sled" "metrics" "k2v" ]
|
||||||
++ (if release then [ "kubernetes-discovery" "telemetry-otlp" "metrics" "lmdb" "sqlite" ] else []);
|
++ (if release then [ "kubernetes-discovery" "telemetry-otlp" "lmdb" "sqlite" ] else []);
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -149,7 +149,10 @@ let
|
|||||||
|
|
||||||
(pkgs.rustBuilder.rustLib.makeOverride {
|
(pkgs.rustBuilder.rustLib.makeOverride {
|
||||||
name = "garage_db";
|
name = "garage_db";
|
||||||
overrideAttrs = drv: { /* [1] */ setBuildEnv = (buildEnv drv); };
|
overrideAttrs = drv: {
|
||||||
|
/* [1] */ setBuildEnv = (buildEnv drv);
|
||||||
|
/* [2] */ hardeningDisable = [ "pie" ];
|
||||||
|
};
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.rustBuilder.rustLib.makeOverride {
|
(pkgs.rustBuilder.rustLib.makeOverride {
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
pkgs:
|
||||||
|
pkgs.buildGoModule rec {
|
||||||
|
pname = "manifest-tool";
|
||||||
|
version = "2.0.5";
|
||||||
|
|
||||||
|
src = pkgs.fetchFromGitHub {
|
||||||
|
owner = "estesp";
|
||||||
|
repo = "manifest-tool";
|
||||||
|
rev = "v${version}";
|
||||||
|
sha256 = "hjCGKnE0yrlnF/VIzOwcDzmQX3Wft+21KCny/opqdLg=";
|
||||||
|
} + "/v2";
|
||||||
|
|
||||||
|
vendorSha256 = null;
|
||||||
|
|
||||||
|
checkPhase = "true";
|
||||||
|
|
||||||
|
meta = with pkgs.lib; {
|
||||||
|
description = "Command line tool to create and query container image manifest list/indexes";
|
||||||
|
homepage = "https://github.com/estesp/manifest-tool";
|
||||||
|
license = licenses.asl20;
|
||||||
|
platforms = platforms.linux;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ let
|
|||||||
overlays = [ cargo2nixOverlay ];
|
overlays = [ cargo2nixOverlay ];
|
||||||
};
|
};
|
||||||
kaniko = (import ./nix/kaniko.nix) pkgs;
|
kaniko = (import ./nix/kaniko.nix) pkgs;
|
||||||
|
manifest-tool = (import ./nix/manifest-tool.nix) pkgs;
|
||||||
winscp = (import ./nix/winscp.nix) pkgs;
|
winscp = (import ./nix/winscp.nix) pkgs;
|
||||||
|
|
||||||
in
|
in
|
||||||
@@ -84,6 +85,34 @@ function to_docker {
|
|||||||
--verbosity=debug
|
--verbosity=debug
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function multiarch_docker {
|
||||||
|
manifest-tool push from-spec <(cat <<EOF
|
||||||
|
image: dxflrs/garage:''${CONTAINER_TAG}
|
||||||
|
manifests:
|
||||||
|
-
|
||||||
|
image: dxflrs/arm64_garage:''${CONTAINER_TAG}
|
||||||
|
platform:
|
||||||
|
architecture: arm64
|
||||||
|
os: linux
|
||||||
|
-
|
||||||
|
image: dxflrs/amd64_garage:''${CONTAINER_TAG}
|
||||||
|
platform:
|
||||||
|
architecture: amd64
|
||||||
|
os: linux
|
||||||
|
-
|
||||||
|
image: dxflrs/386_garage:''${CONTAINER_TAG}
|
||||||
|
platform:
|
||||||
|
architecture: 386
|
||||||
|
os: linux
|
||||||
|
-
|
||||||
|
image: dxflrs/arm_garage:''${CONTAINER_TAG}
|
||||||
|
platform:
|
||||||
|
architecture: arm
|
||||||
|
os: linux
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function refresh_index {
|
function refresh_index {
|
||||||
aws \
|
aws \
|
||||||
--endpoint-url https://garage.deuxfleurs.fr \
|
--endpoint-url https://garage.deuxfleurs.fr \
|
||||||
@@ -113,6 +142,7 @@ function refresh_index {
|
|||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
pkgs.awscli2
|
pkgs.awscli2
|
||||||
kaniko
|
kaniko
|
||||||
|
manifest-tool
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,10 @@ pub struct AdminApiServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AdminApiServer {
|
impl AdminApiServer {
|
||||||
pub fn new(garage: Arc<Garage>) -> Self {
|
pub fn new(
|
||||||
|
garage: Arc<Garage>,
|
||||||
|
#[cfg(feature = "metrics")] exporter: PrometheusExporter,
|
||||||
|
) -> Self {
|
||||||
let cfg = &garage.config.admin;
|
let cfg = &garage.config.admin;
|
||||||
let metrics_token = cfg
|
let metrics_token = cfg
|
||||||
.metrics_token
|
.metrics_token
|
||||||
@@ -47,7 +50,7 @@ impl AdminApiServer {
|
|||||||
Self {
|
Self {
|
||||||
garage,
|
garage,
|
||||||
#[cfg(feature = "metrics")]
|
#[cfg(feature = "metrics")]
|
||||||
exporter: opentelemetry_prometheus::exporter().init(),
|
exporter,
|
||||||
metrics_token,
|
metrics_token,
|
||||||
admin_token,
|
admin_token,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -174,7 +174,11 @@ impl<A: ApiHandler> ApiServer<A> {
|
|||||||
|
|
||||||
let current_context = Context::current();
|
let current_context = Context::current();
|
||||||
let current_span = current_context.span();
|
let current_span = current_context.span();
|
||||||
current_span.update_name::<String>(format!("S3 API {}", endpoint.name()));
|
current_span.update_name::<String>(format!(
|
||||||
|
"{} API {}",
|
||||||
|
A::API_NAME_DISPLAY,
|
||||||
|
endpoint.name()
|
||||||
|
));
|
||||||
current_span.set_attribute(KeyValue::new("endpoint", endpoint.name()));
|
current_span.set_attribute(KeyValue::new("endpoint", endpoint.name()));
|
||||||
endpoint.add_span_attributes(current_span);
|
endpoint.add_span_attributes(current_span);
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ pub async fn run_server(config_file: PathBuf) -> Result<(), Error> {
|
|||||||
|
|
||||||
// ---- Initialize Garage internals ----
|
// ---- Initialize Garage internals ----
|
||||||
|
|
||||||
|
#[cfg(feature = "metrics")]
|
||||||
|
let metrics_exporter = opentelemetry_prometheus::exporter().init();
|
||||||
|
|
||||||
info!("Initializing background runner...");
|
info!("Initializing background runner...");
|
||||||
let watch_cancel = netapp::util::watch_ctrl_c();
|
let watch_cancel = netapp::util::watch_ctrl_c();
|
||||||
let (background, await_background_done) = BackgroundRunner::new(16, watch_cancel.clone());
|
let (background, await_background_done) = BackgroundRunner::new(16, watch_cancel.clone());
|
||||||
@@ -50,7 +53,11 @@ pub async fn run_server(config_file: PathBuf) -> Result<(), Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
info!("Initialize Admin API server and metrics collector...");
|
info!("Initialize Admin API server and metrics collector...");
|
||||||
let admin_server = AdminApiServer::new(garage.clone());
|
let admin_server = AdminApiServer::new(
|
||||||
|
garage.clone(),
|
||||||
|
#[cfg(feature = "metrics")]
|
||||||
|
metrics_exporter,
|
||||||
|
);
|
||||||
|
|
||||||
info!("Launching internal Garage cluster communications...");
|
info!("Launching internal Garage cluster communications...");
|
||||||
let run_system = tokio::spawn(garage.system.clone().run(watch_cancel.clone()));
|
let run_system = tokio::spawn(garage.system.clone().run(watch_cancel.clone()));
|
||||||
|
|||||||
Reference in New Issue
Block a user