✓ Solved

Is it possible to attach an existing volume while creating a new linode?

I want to attach an existing volume to a new linode during creation. Is it possible?

The result I want to achieve is to use StackScript to mount the volume automatically. I cannot do it if I attach the volume after the linode is running.

5 Replies

✓ Best Answer

My understanding is that for /dev/disk/by-id/scsi-0Linode_Volume_My_Volume to be available, it has to be attached first, using Linode UI or API. Am I right?

Yes. The Linode API has a plethora of methods for dealing with block storage volumes:

See: https://www.linode.com/docs/api/volumes/

Using the API is how I would try to do it. Hopefully, stack scripts have some mechanism for doing Linode API calls. If you can't do it before the Linode is instanced, you could maybe do it when the system boots up. You would have to do it AFTER networking is enabled but BEFORE /etc/fstab is processed. You'd have to write a (very reliable) systemd service that runs your shell script:

https://www.freecodecamp.org/news/the-linux-booting-process-6-steps-described-in-detail/

I use the Linode API to update my DKIM public key in a cron job once a month (involves updating a DNS TXT record).

-- sw

So, I don't know anything about stack scripts. Given that…

I want to attach an existing volume to a new linode during creation. Is it possible?

My assumptions:

  1. You're talking about a block storage volume..those would be the only ones that would be pre-existing when you create a Linode.
  2. Your stack script can manipulate /etc/fstab in the image you're trying to instance or you have a custom image with the /etc/fstab that you want/need.
  3. Your stack script can create the mount point in the image you're trying to instance or you have a custom image with the mount point that you want/need.

Given all that,

  1. Insert an entry into /etc/fstab in your image that looks something like:
# The first item in the entry is the id that Linode gave your 
# block storage volume when you created it.
#
/dev/disk/by-id/scsi-0Linode_Volume_My_Volume /the/mount/point ext4 defaults 0 0
  1. Create the mount point /the/mount/point in your image:
[ -d /the/mount/point ] || mkdir -p /the/mount/point
  1. Provision and boot the instance…systemd should take care of the rest.

See: https://sslhow.com/understanding-etc-fstab-file-in-linux

Like I said, I don't know anything about stack scripts, how to write them or what they can do so this may all just be a lot of who-shot-john. Use at your own risk!

I hope this helps…

-- sw

PS. If your intent here is to share a block storage volume among multiple instances…boy howdy!!!, I'd check with Linode support and make sure you can do that first. You may be heading off a cliff…

Thank you for your reply!

My understanding is that for /dev/disk/by-id/scsi-0Linode_Volume_My_Volume to be available, it has to be attached first, using Linode UI or API. Am I right?

That means I have to attach the volume manually after creating a new linode. The rest is easy….

If it is not possible, I would just do it by hand then.

I've found the solution using stackscript.

Assuming that a volume is already created with filesystem, my use case is to always attach the volume and mount it when creating my new linode instance.

When I was checking the docker stackscript, I found a stackscript (API Functions Helper) that can handle the volumes API calls in bash.
To use it, simply add attach_volume VOLUMN_LABEL in stackscript and pass in a API token (linode:read+write, volume:read+write) in stackscript_data in linode-cli.

e.g. based on the docker stackscript, add a line to call attach_volume and add 2 lines to mount

#!/usr/bin/env bash
### UDF Variables
## Docker Settings
#<UDF name="dockerfile"  Label="Resource to download?" example="URL to Dockerfile or docker-compose.yml" default="">
#<UDF name="runcmd" Label="Command to run?" example="docker run --name spigot --restart unless-stopped -e JVM_OPTS=-Xmx4096M -p 25565:25565 -itd example/docker-spigot" default="">
## Linode/SSH Security Settings
#<UDF name="username" label="The limited sudo user to be created for the Linode" default="">
#<UDF name="password" label="The password for the limited sudo user" default="">
#<UDF name="pubkey" label="The SSH Public Key that will be used to access the Linode" default="">
#<UDF name="disable_root" label="Disable root access over SSH?" oneOf="Yes,No" default="No">
## Domain Settings
#<UDF name="token_password" label="Your Linode API token. This is required if filling out any of the domain-related fields." default="">
#<UDF name="subdomain" label="The subdomain for your server" default="">
#<UDF name="domain" label="Your domain" default="">
#<UDF name="soa_email_address" label="Admin Email for the server" default="">
#<UDF name="mx" label="Do you need an MX record for this domain? (Yes if sending mail from this Linode)" oneOf="Yes,No" default="No">
#<UDF name="spf" label="Do you need an SPF record for this domain? (Yes if sending mail from this Linode)" oneOf="Yes,No" default="No">
### Logging and other debugging helpers
## Enable logging for the StackScript
exec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1
# Source the Linode Bash StackScript, API, and OCA Helper libraries
source <ssinclude StackScriptID=1>
source <ssinclude StackScriptID=632759>
source <ssinclude StackScriptID=401712>
# Source and run the New Linode Setup script for DNS/SSH configuration
source <ssinclude StackScriptID=666912>

# Done loading others stackscript, able to call attach_volume here
attach_volume mydata

## Local functions used by this script
function docker_ce_install {
    # Install the dependencies & add Docker to the APT repository
    system_install_package apt-transport-https ca-certificates curl software-properties-common gnupg2
    curl -fsSL https://download.docker.com/linux/"${detected_distro[distro]}"/gpg | apt-key add -
    add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/"${detected_distro[distro]}" $(lsb_release -cs) stable"
    # Update & install Docker-CE
    apt_setup_update 
    system_install_package docker-ce
}
function docker_compose_install {
    # Install Docker Compose
    curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
    chmod +x /usr/local/bin/docker-compose
    docker-compose --version
    docker-compose up
}
# Remove any existing Docker installations
system_remove_package docker docker-engine docker.io
# Download the Dockerfile, if specified
[ "$DOCKERFILE" ] && curl -LO "$DOCKERFILE"
# Install Docker CE and Docker Compose
docker_ce_install
docker_compose_install
# Configure the firewall
## code will go here

# Since the attach volume seems to take some time (>5s) before really exist in /dev/disk/by-id/, I choose to mount it after all the above installation thing
# Mount Volume
mkdir /mnt/mydata
mount /dev/disk/by-id/scsi-0Linode_Volume_mydata /mnt/mydata

# Wait 2 seconds, then run the container
sleep 2
[ "$RUNCMD" ] && $RUNCMD &

Lastly, when creating linode, pass the token_password and the custom stackscript_id

linode-cli linodes create \
  --image 'linode/ubuntu20.04' \
  --region ap-west \
  --type g6-dedicated-2 \
  --label docker-mc\
  --root_pass 'MY_ROOT_PASS' \
  --booted true \
  --backups_enabled false \
  --private_ip false \
  --stackscript_id my_stackscript_id \
  --stackscript_data ' {"token_password": "MY_API_TOKEN"}'

It should be mounted after stackscript is completed.
For debugging issue, check the log file less /var/log/stackscript.log.

Reply

Please enter an answer
Tips:

You can mention users to notify them: @username

You can use Markdown to format your question. For more examples see the Markdown Cheatsheet.

> I’m a blockquote.

I’m a blockquote.

[I'm a link] (https://www.google.com)

I'm a link

**I am bold** I am bold

*I am italicized* I am italicized

Community Code of Conduct