feat: one-line install script (#1924)

* feat: one-line install script

* remove homebrew support

* remove arch linux

* use proper filename for packages

* fix variable format

* fix systemd instructions

* fixes to standalone script

* fix missing var bugs

* fix standalone install

* fix for MacOS

* format

* fix armv7 assets and zips

* remove windows

* update install docs

* support external sources with shellcheck

* shfmt

* add external sources to GitHub action & unfold

* change wording

* first template docs

* default to /usr/local instead

* add option for binary name
This commit is contained in:
Ben Potter 2022-06-01 14:15:09 -05:00 committed by GitHub
parent f5a8d17aa8
commit 46ffb67d60
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 641 additions and 82 deletions

View File

@ -52,6 +52,8 @@ jobs:
- uses: actions/checkout@v3
- name: Run ShellCheck
uses: ludeeus/action-shellcheck@1.1.0
env:
SHELLCHECK_OPTS: --external-sources
with:
ignore: node_modules

View File

@ -71,7 +71,7 @@ lint/go:
# Use shfmt to determine the shell files, takes editorconfig into consideration.
lint/shellcheck: $(shell shfmt -f .)
@echo "--- shellcheck"
shellcheck $(shell shfmt -f .)
shellcheck --external-sources $(shell shfmt -f .)
peerbroker/proto/peerbroker.pb.go: peerbroker/proto/peerbroker.proto
protoc \

View File

@ -56,47 +56,25 @@ You can use any Web IDE ([code-server](https://github.com/coder/code-server), [p
## Installing Coder
We recommend installing [the latest
release](https://github.com/coder/coder/releases) on a system with at least 1
CPU core and 2 GB RAM:
There are a few ways to install Coder: [install script](./docs/install.md#installsh) (macOS, Linux), [docker-compose](./docs/install.md#docker-compose), or [manually](./docs/install.md#manual) via the latest release (macOS, Windows, and Linux).
1. Download the [release asset](https://github.com/coder/coder/releases) appropriate for your operating system
1. Unzip the folder you just downloaded, and move the `coder` executable to a location that's on your `PATH`
If you use the install script, you can preview what occurs during the install process:
```sh
# ex. MacOS and Linux
mv coder /usr/local/bin
```
```sh
curl -fsSL https://coder.com/install.sh | sh -s -- --dry-run
```
Windows: see [this guide](https://answers.microsoft.com/en-us/windows/forum/all/adding-path-variable/97300613-20cb-4d85-8d0e-cc9d3549ba23) on adding a folder to `PATH`
To install, run:
There are a few ways to run Coder:
```sh
curl -fsSL https://coder.com/install.sh | sh
```
- To run a **temporary deployment**, start with dev mode (all data is in-memory and destroyed on exit):
Once installed, you can run a temporary deployment in dev mode (all data is in-memory and destroyed on exit):
```bash
coder server --dev
```
- To run a **production deployment** with PostgreSQL:
```bash
CODER_PG_CONNECTION_URL="postgres://<username>@<host>/<database>?password=<password>" \
coder server
```
- To run as a **system service**, install with `.deb` (Debian, Ubuntu) or `.rpm` (Fedora, CentOS, RHEL, SUSE):
```bash
# Edit the configuration!
sudo vim /etc/coder.d/coder.env
sudo service coder restart
```
> macOS and Windows users: You'll need to write your own
> configuration to run Coder as a system service.
- See the [installation guide](./docs/install.md) for additional ways to run Coder (e.g., docker-compose)
```sh
coder server --dev
```
Use `coder --help` to get a complete list of flags and environment variables.

View File

@ -2,6 +2,58 @@
This article walks you through the various ways of installing and deploying Coder.
## install.sh
The easiest way to install Coder is to use our [install script](https://github.com/coder/coder/main/install.sh) for Linux and macOS. The install script
attempts to use the system package manager detection-reference if possible.
You can preview what occurs during the install process:
```bash
curl -L https://coder.com/install.sh | sh -s -- --dry-run
```
To install, run:
```bash
curl -L https://coder.com/install.sh | sh
```
> If you're concerned about the install script's use of `curl | sh` and the
> security implications, please see [this blog
> post](https://sandstorm.io/news/2015-09-24-is-curl-bash-insecure-pgp-verified-install)
> by [sandstorm.io](https://sandstorm.io).
You can modify the installation process by including flags. Run the help command for reference:
```bash
curl -L https://coder.com/install.sh | sh -s -- --help
```
## System packages
Coder publishes the following system packages [in GitHub releases](https://github.com/coder/coder/releases):
- .deb (Debian, Ubuntu)
- .rpm (Fedora, CentOS, RHEL, SUSE)
- .apk (Alpine)
Once installed, you can run Coder as a system service:
```sh
# Specify a PostgreSQL database
# in the configuration first:
sudo vim /etc/coder.d/coder.env
sudo service coder restart
```
Or run a **temporary deployment** with dev mode (all data is in-memory and destroyed on exit):
```sh
coder server --dev
```
## docker-compose
Before proceeding, please ensure that you have both Docker and the [latest version of
@ -40,62 +92,34 @@ Coder](https://github.com/coder/coder/releases) installed.
ghcr.io/coder/coder:v0.5.10
```
1. Open a new terminal window, and run `coder login <yourAccessURL>` to create
your first user (once you've done so, you can navigate to `yourAccessURL` and
log in with these credentials).
1. Follow the on-screen instructions to create your first template and workspace
1. Next, copy a sample template into a new directory so that you can create a custom template in a
subsequent step (be sure that you're working in the directory where you want
your templates stored):
## Manual
```console
coder templates init
```
We publish self-contained .zip and .tar.gz archives in [GitHub releases](https://github.com/coder/coder/releases). The archives bundle `coder` binary.
Choose the "Develop in Docker" example to generate a sample template in the
`docker` subdirectory.
1. Download the [release archive](https://github.com/coder/coder/releases) appropriate for your operating system
1. Navigate into the new directory and create a new template:
1. Unzip the folder you just downloaded, and move the `coder` executable to a location that's on your `PATH`
```console
cd docker
coder templates create
```sh
# ex. MacOS and Linux
mv coder /usr/local/bin
```
Follow the prompts displayed to proceed. When done, you'll see the following
message:
> Windows users: see [this guide](https://answers.microsoft.com/en-us/windows/forum/all/adding-path-variable/97300613-20cb-4d85-8d0e-cc9d3549ba23) for adding folders to `PATH`.
```console
The docker template has been created! Developers can
provision a workspace with this template using:
1. Start a Coder server
coder create --template="docker" [workspace name]
To run a **temporary deployment**, start with dev mode (all data is in-memory and destroyed on exit):
```bash
coder server --dev
```
1. At this point, you're ready to provision your first workspace:
To run a **production deployment** with PostgreSQL:
```console
coder create --template="docker" [workspace name]
```bash
CODER_PG_CONNECTION_URL="postgres://<username>@<host>/<database>?password=<password>" \
coder server
```
Follow the on-screen prompts to set the parameters for your workspace. If
the process is successful, you'll get information regarding your workspace:
```console
┌─────────────────────────────────────────────────────────────────┐
│ RESOURCE STATUS ACCESS │
├─────────────────────────────────────────────────────────────────┤
│ docker_container.workspace ephemeral │
│ └─ dev (linux, amd64) ⦾ connecting [0s] coder ssh main │
├─────────────────────────────────────────────────────────────────┤
│ docker_volume.coder_volume ephemeral │
└─────────────────────────────────────────────────────────────────┘
The main workspace has been created!
```
You can now access your workspace via your web browser by navigating to your
access URL, or you can connect to it via SSH by running:
```console
coder ssh [workspace name]
```

555
install.sh Executable file
View File

@ -0,0 +1,555 @@
#!/bin/sh
set -eu
# Coder's automatic install script.
# See https://github.com/coder/coder#installing-coder
usage() {
arg0="$0"
if [ "$0" = sh ]; then
arg0="curl -fsSL https://coder.com/install.sh | sh -s --"
else
not_curl_usage="The latest script is available at https://coder.com/install.sh
"
fi
cath <<EOF
Installs Coder.
It tries to use the system package manager if possible.
After successful installation it explains how to start Coder.
Pass in user@host to install Coder on user@host over ssh.
The remote host must have internet access.
${not_curl_usage-}
Usage:
$arg0 [--dry-run] [--version X.X.X] [--edge] [--method detect] \
[--prefix ~/.local] [--rsh ssh] [user@host]
--dry-run
Echo the commands for the install process without running them.
--version X.X.X
Install a specific version instead of the latest.
--edge
Install the latest edge version instead of the latest stable version.
--method [detect | standalone]
Choose the installation method. Defaults to detect.
- detect detects the system package manager and tries to use it.
Full reference on the process is further below.
- standalone installs a standalone release archive into /usr/local/bin
--prefix <dir>
Sets the prefix used by standalone release archives. Defaults to /usr/local
and the binary is copied into /usr/local/bin
To install in \$HOME, pass ---prefix=\$HOME/.local
--binary-name <name>
Sets the name for the CLI in standalone release archives. Defaults to "coder"
To use the CLI as coder2, pass --binary-name=coder2
Note: in-product documentation will always refer to the CLI as "coder"
--rsh <bin>
Specifies the remote shell for remote installation. Defaults to ssh.
The detection method works as follows:
- Debian, Ubuntu, Raspbian: install the deb package from GitHub.
- Fedora, CentOS, RHEL, openSUSE: install the rpm package from GitHub.
- Alpine: install the apk package from GitHub.
- macOS: install the release from GitHub.
- All others: install the release from GitHub.
We build releases on GitHub for amd64, armv7, and arm64 on Windows, Linux, and macOS.
When the detection method tries to pull a release from GitHub it will
fall back to installing standalone when there is no matching release for
the system's operating system and architecture.
The installer will cache all downloaded assets into ~/.cache/coder
EOF
}
echo_latest_version() {
if [ "${EDGE-}" ]; then
version="$(curl -fsSL https://api.github.com/repos/coder/coder/releases | awk 'match($0,/.*"html_url": "(.*\/releases\/tag\/.*)".*/)' | head -n 1 | awk -F '"' '{print $4}')"
else
# https://gist.github.com/lukechilds/a83e1d7127b78fef38c2914c4ececc3c#gistcomment-2758860
version="$(curl -fsSLI -o /dev/null -w "%{url_effective}" https://github.com/coder/coder/releases/latest)"
fi
version="${version#https://github.com/coder/coder/releases/tag/}"
version="${version#v}"
echo "$version"
}
echo_standalone_postinstall() {
cath <<EOF
Standalone release has been installed into $STANDALONE_INSTALL_PREFIX/bin/$STANDALONE_BINARY_NAME
EOF
if [ "$STANDALONE_INSTALL_PREFIX" != /usr/local ]; then
cath <<EOF
Extend your path to use Coder:
PATH="$STANDALONE_INSTALL_PREFIX/bin:\$PATH"
EOF
fi
cath <<EOF
Run Coder (temporary):
$STANDALONE_BINARY_NAME server --dev
Or run a production deployment with PostgreSQL:
CODER_PG_CONNECTION_URL="postgres://<username>@<host>/<database>?password=<password>" \\
$STANDALONE_BINARY_NAME server
EOF
}
echo_systemd_postinstall() {
echoh
cath <<EOF
$1 package has been installed.
To run Coder as a system service:
# Configure the PostgreSQL database for Coder
sudo vim /etc/coder.d/coder.env
# Have systemd start Coder now and restart on boot
sudo systemctl enable --now coder
Or, run a temporary deployment (all data is in-memory
and destroyed on exit):
coder server --dev
EOF
}
main() {
if [ "${TRACE-}" ]; then
set -x
fi
unset \
DRY_RUN \
METHOD \
OPTIONAL \
ALL_FLAGS \
RSH_ARGS \
EDGE \
RSH
ALL_FLAGS=""
while [ "$#" -gt 0 ]; do
case "$1" in
-*)
ALL_FLAGS="${ALL_FLAGS} $1"
;;
esac
case "$1" in
--dry-run)
DRY_RUN=1
;;
--method)
METHOD="$(parse_arg "$@")"
shift
;;
--method=*)
METHOD="$(parse_arg "$@")"
;;
--prefix)
STANDALONE_INSTALL_PREFIX="$(parse_arg "$@")"
shift
;;
--prefix=*)
STANDALONE_INSTALL_PREFIX="$(parse_arg "$@")"
;;
--binary-name)
STANDALONE_BINARY_NAME="$(parse_arg "$@")"
shift
;;
--binary-name=*)
STANDALONE_BINARY_NAME="$(parse_arg "$@")"
;;
--version)
VERSION="$(parse_arg "$@")"
shift
;;
--version=*)
VERSION="$(parse_arg "$@")"
;;
--edge)
EDGE=1
;;
--rsh)
RSH="$(parse_arg "$@")"
shift
;;
--rsh=*)
RSH="$(parse_arg "$@")"
;;
-h | --h | -help | --help)
usage
exit 0
;;
--)
shift
# We remove the -- added above.
ALL_FLAGS="${ALL_FLAGS% --}"
RSH_ARGS="$*"
break
;;
-*)
echoerr "Unknown flag $1"
echoerr "Run with --help to see usage."
exit 1
;;
*)
RSH_ARGS="$*"
break
;;
esac
shift
done
if [ "${RSH_ARGS-}" ]; then
RSH="${RSH-ssh}"
echoh "Installing remotely with $RSH $RSH_ARGS"
curl -fsSL https://coder.dev/install.sh | prefix "$RSH_ARGS" "$RSH" "$RSH_ARGS" sh -s -- "$ALL_FLAGS"
return
fi
METHOD="${METHOD-detect}"
if [ "$METHOD" != detect ] && [ "$METHOD" != standalone ]; then
echoerr "Unknown install method \"$METHOD\""
echoerr "Run with --help to see usage."
exit 1
fi
# These are used by the various install_* functions that make use of GitHub
# releases in order to download and unpack the right release.
CACHE_DIR=$(echo_cache_dir)
STANDALONE_INSTALL_PREFIX=${STANDALONE_INSTALL_PREFIX:-/usr/local}
STANDALONE_BINARY_NAME=${STANDALONE_BINARY_NAME:-coder}
VERSION=${VERSION:-$(echo_latest_version)}
# These can be overridden for testing but shouldn't normally be used as it can
# result in a broken coder.
OS=${OS:-$(os)}
ARCH=${ARCH:-$(arch)}
distro_name
# Standalone installs by pulling pre-built releases from GitHub.
if [ "$METHOD" = standalone ]; then
if has_standalone; then
install_standalone
exit 0
else
echoerr "There are no standalone releases for $ARCH"
echoerr "Please try again without '--method standalone'"
exit 1
fi
fi
# DISTRO can be overridden for testing but shouldn't normally be used as it
# can result in a broken coder.
DISTRO=${DISTRO:-$(distro)}
case $DISTRO in
# macOS uses the standalone installation for now.
# Homebrew support is planned. See: https://github.com/coder/coder/issues/1925
macos) install_standalone ;;
# The .deb and .rpm files are pulled from GitHub.
debian) install_deb ;;
fedora | opensuse) install_rpm ;;
# We don't have GitHub releases that work on Alpine or FreeBSD so we have no
# choice but to use npm here.
alpine) install_apk ;;
# For anything else we'll try to install standalone but fall back to npm if
# we don't have releases for the architecture.
*)
echoh "Unsupported package manager."
echoh "Falling back to standalone installation."
install_standalone
;;
esac
}
parse_arg() {
case "$1" in
*=*)
# Remove everything after first equal sign.
opt="${1%%=*}"
# Remove everything before first equal sign.
optarg="${1#*=}"
if [ ! "$optarg" ] && [ ! "${OPTIONAL-}" ]; then
echoerr "$opt requires an argument"
echoerr "Run with --help to see usage."
exit 1
fi
echo "$optarg"
return
;;
esac
case "${2-}" in
"" | -*)
if [ ! "${OPTIONAL-}" ]; then
echoerr "$1 requires an argument"
echoerr "Run with --help to see usage."
exit 1
fi
;;
*)
echo "$2"
return
;;
esac
}
fetch() {
URL="$1"
FILE="$2"
if [ -e "$FILE" ]; then
echoh "+ Reusing $FILE"
return
fi
sh_c mkdir -p "$CACHE_DIR"
sh_c curl \
-#fL \
-o "$FILE.incomplete" \
-C - \
"$URL"
sh_c mv "$FILE.incomplete" "$FILE"
}
install_deb() {
echoh "Installing v$VERSION of the $ARCH deb package from GitHub."
echoh
fetch "https://github.com/coder/coder/releases/download/v$VERSION/coder_${VERSION}_${OS}_${ARCH}.deb" \
"$CACHE_DIR/coder_${VERSION}_$ARCH.deb"
sudo_sh_c dpkg -i "$CACHE_DIR/coder_${VERSION}_$ARCH.deb"
echo_systemd_postinstall deb
}
install_rpm() {
echoh "Installing v$VERSION of the $ARCH rpm package from GitHub."
echoh
fetch "https://github.com/coder/coder/releases/download/v$VERSION/coder_${VERSION}_${OS}_${ARCH}.rpm" \
"$CACHE_DIR/coder_${VERSION}_${OS}_${ARCH}.rpm"
sudo_sh_c rpm -i "$CACHE_DIR/coder_${VERSION}_${OS}_${ARCH}.rpm"
echo_systemd_postinstall rpm
}
install_apk() {
echoh "Installing v$VERSION of the $ARCH apk package from GitHub."
echoh
fetch "https://github.com/coder/coder/releases/download/v$VERSION/coder_${VERSION}_${OS}_${ARCH}.apk" \
"$CACHE_DIR/coder_${VERSION}_${OS}_${ARCH}.apk"
sudo_sh_c apk add --allow-untrusted "$CACHE_DIR/coder_${VERSION}_${OS}_${ARCH}.apk"
echo_systemd_postinstall apk
}
install_standalone() {
echoh "Installing v$VERSION of the $ARCH release from GitHub."
echoh
# MacOS releases are packaged as .zip
case $OS in
darwin) STANDALONE_ARCHIVE_FORMAT=zip ;;
*) STANDALONE_ARCHIVE_FORMAT=tar.gz ;;
esac
fetch "https://github.com/coder/coder/releases/download/v$VERSION/coder_${VERSION}_${OS}_${ARCH}.$STANDALONE_ARCHIVE_FORMAT" \
"$CACHE_DIR/coder_${VERSION}_${OS}_${ARCH}.$STANDALONE_ARCHIVE_FORMAT"
# -w only works if the directory exists so try creating it first. If this
# fails we can ignore the error as the -w check will then swap us to sudo.
sh_c mkdir -p "$STANDALONE_INSTALL_PREFIX" 2>/dev/null || true
sh_c="sh_c"
if [ ! -w "$STANDALONE_INSTALL_PREFIX" ]; then
sh_c="sudo_sh_c"
fi
"$sh_c" mkdir -p "$STANDALONE_INSTALL_PREFIX/bin"
if [ "$STANDALONE_ARCHIVE_FORMAT" = tar.gz ]; then
"$sh_c" tar -C "$CACHE_DIR" -xzf "$CACHE_DIR/coder_${VERSION}_${OS}_${ARCH}.tar.gz"
else
"$sh_c" unzip -d "$CACHE_DIR" -o "$CACHE_DIR/coder_${VERSION}_${OS}_${ARCH}.zip"
fi
"$sh_c" cp "$CACHE_DIR/coder" "$STANDALONE_INSTALL_PREFIX/bin/$STANDALONE_BINARY_NAME"
echo_standalone_postinstall
}
# Determine if we have standalone releases on GitHub for the system's arch.
has_standalone() {
case $ARCH in
amd64) return 0 ;;
ard64) return 0 ;;
armv7)
[ "$(distro)" != darwin ]
return
;;
*) return 1 ;;
esac
}
os() {
uname="$(uname)"
case $uname in
Linux) echo linux ;;
Darwin) echo darwin ;;
FreeBSD) echo freebsd ;;
*) echo "$uname" ;;
esac
}
# Print the detected Linux distro, otherwise print the OS name.
#
# Example outputs:
# - darwin -> darwin
# - freebsd -> freebsd
# - ubuntu, raspbian, debian ... -> debian
# - amzn, centos, rhel, fedora, ... -> fedora
# - opensuse-{leap,tumbleweed} -> opensuse
# - alpine -> alpine
# - arch -> arch
#
# Inspired by https://github.com/docker/docker-install/blob/26ff363bcf3b3f5a00498ac43694bf1c7d9ce16c/install.sh#L111-L120.
distro() {
if [ "$OS" = "darwin" ] || [ "$OS" = "freebsd" ]; then
echo "$OS"
return
fi
if [ -f /etc/os-release ]; then
(
. /etc/os-release
if [ "${ID_LIKE-}" ]; then
for id_like in $ID_LIKE; do
case "$id_like" in debian | fedora | opensuse)
echo "$id_like"
return
;;
esac
done
fi
echo "$ID"
)
return
fi
}
# Print a human-readable name for the OS/distro.
distro_name() {
if [ "$(uname)" = "Darwin" ]; then
echo "macOS v$(sw_vers -productVersion)"
return
fi
if [ -f /etc/os-release ]; then
(
. /etc/os-release
echo "$PRETTY_NAME"
)
return
fi
# Prints something like: Linux 4.19.0-9-amd64
uname -sr
}
arch() {
uname_m=$(uname -m)
case $uname_m in
aarch64) echo arm64 ;;
x86_64) echo amd64 ;;
armv7l) echo armv7 ;;
*) echo "$uname_m" ;;
esac
}
command_exists() {
if [ ! "$1" ]; then return 1; fi
command -v "$@" >/dev/null
}
sh_c() {
echoh "+ $*"
if [ ! "${DRY_RUN-}" ]; then
sh -c "$*"
fi
}
sudo_sh_c() {
if [ "$(id -u)" = 0 ]; then
sh_c "$@"
elif command_exists sudo; then
sh_c "sudo $*"
elif command_exists su; then
sh_c "su - -c '$*'"
else
echoh
echoerr "This script needs to run the following command as root."
echoerr " $*"
echoerr "Please install sudo or su."
exit 1
fi
}
echo_cache_dir() {
if [ "${XDG_CACHE_HOME-}" ]; then
echo "$XDG_CACHE_HOME/coder"
elif [ "${HOME-}" ]; then
echo "$HOME/.cache/coder"
else
echo "/tmp/coder-cache"
fi
}
echoh() {
echo "$@" | humanpath
}
cath() {
humanpath
}
echoerr() {
echoh "$@" >&2
}
# humanpath replaces all occurrences of " $HOME" with " ~"
# and all occurrences of '"$HOME' with the literal '"$HOME'.
humanpath() {
sed "s# $HOME# ~#g; s#\"$HOME#\"\$HOME#g"
}
# We need to make sure we exit with a non zero exit if the command fails.
# /bin/sh does not support -o pipefail unfortunately.
prefix() {
PREFIX="$1"
shift
fifo="$(mktemp -d)/fifo"
mkfifo "$fifo"
sed -e "s#^#$PREFIX: #" "$fifo" &
"$@" >"$fifo" 2>&1
}
main "$@"