What is Octopus Deploy
Octopus helps deployment applications to multi-cloud, hybrid-cloud and on-premises easier.
Under their product dropdown it has 'solutions' and 'features'. All the solutions appear to be the same product, but marketed differently depending on the end deployment target or integration point.
Features
They have a features page. Let's dissect that as a starting point in understanding what this product does.
First they claim 'Powerful DevOps automation'.
Octopus Deploy makes it easy to automate your deployments and operations runbooks from a single place, helping you ship code faster, improve reliability, and break down dev & ops silos.
So they must have CICD system integrations. They repeat that again in the next feature 'Complete your CI/CD pipeline'.
I love this infographic:
This is how to make a product look adoptable for a software nerd - a getting started that fits on one page!
Let's break this down. 'Define your process' sounds like writing the delivery segment of your CICD pipeline, which maybe already exists but this must mean you re-create it using their tool, which presumably makes it straight-forward to target all sorts of systems. Then the next two steps are setting variables and hitting deploy.
Next they quickly flex their dashboard where you can see deployed app versions.
Over 450 Steps Looks like they have a huge library of 'steps'. To someone not familiar this sounds terrible, but
steps
in Github actions are little pieces of your CICD pipeline you can slot in to link up useful functionality.
They've amassed a ton of scripts.
This is pretty sweet, in their Pricing they have a pretty comprehensive free tier. Likely this has drawn in a huge number of the types of people who are contributing to FOSS projects, and they've in turn latched onto this as the platform to share their CICD steps with. Octopus get's the help of free integrations from the community by continuing to offer a great free use license in good faith. Let's hope they don't pull a Docker Registry move, or more recently a Unity Installation Fee move.
Finally we get to the section where they define where you can deploy:
It seems decently comprehensive! You can deploy to the three major cloud providers, directly to Kubernetes or onto a VM. I can't wait to learn how the VM agent works that sounds like a novel approach from anything else I've seen.
They also offer an 'operations control center' as you would expect from these solutions. Likely they have a hosted SaaS offering around this that they make most of their revenue from.
I'm excited to dig into what they've implemented for the runbooks and what self-service operations they decided were critical.
They talk for a section about version controlled releases and that you can integrate your CI with git.
Work where you're the most productive This section says they have a web UI to edit pipelines or a VSCode extension. What sticks out to me here is they've actually implemented their own product specific language, extension
.ocl
. I'm not sure I'm a fan of that part but we'll see.
Opinionated Software They're forcing specific rules and behaviors:
- Build once: Don't rebuild tested dev on prod and push to prod, just re-tag the dev image
- For deployments, do your best! Don't 'fail early, fail fast'
- No YAML! They say they do this to help people who can't program, but they could achieve that while also using YAML?
- Downtime minimized during deployment: blue-green, canary, rolling deployments
flexibility
apparently they've build 'escape hatches' to let you work around their rules if you need to
On-prem like a boss 'Tentacle agent' creates a 'two-way trust relationship... alternatively... SSH'. This is saying that their Agent establishes a VPN connection between the On Prem site and their hosted operations platform, if VPN won't work they can use SSH.
'Push or Pull':
Tentacle can be set up either in listening mode (like SSH or PowerShell remoting), or polling mode (like RabbitMQ or Jenkins build agents). This gives you full control when it comes to firewalls and how Octopus interacts within your network.
'Proxies and advanced network topologies'
Octopus and Tentacle communicate over HTTPS, and can navigate proxy servers. That makes it possible to use Octopus across DMZ's, or to set up proxy servers as a jump box into a private network. If there's a way to get bits between networks, Octopus and Tentacle can usually find some way to navigate it.
This all together is a really awesome model. For environments an open internet connection, a tunnel is configured, and deployments are clear.
It can then deal with proxies and advanced network topologies, taking care of environments with DMZ's, or lets you setup a proxy server as a jump box. I'll certainly need to dig into how this works, cool!
Finally it can handle multi-tenant deployments and they say their support is useful.
Summary
So far my understanding of the product by reading the marketing material is that Octopus is:
- A CICD framework focused on simplifying deployments
- It can target almost any execution environment
- A client-side runtime agent and collecting web server, providing an operations dashboard for the vendor
- A suite of network hopping tools and configurations to support Air Gapped environments
Docs
Next I went through the documentation.
Vendor Portal
Getting started seems like a good starting point. The first step appears to be choosing how you're going to host their Vendor Portal 'Octopus Server'. They have a cloud hosted product which likely costs more, and a self-hosted product you can start with for free.
The installation document is more interesting than I was expecting. There're two installation options:
- Windows Service, which wraps a linux container
- Linux Container
The container includes the web application and REST API. But, the container is stateful! Meaning there's persistent data written to the container volume itself rather than everything being stored in the database - this is slightly awkward as it defies a principle of the 12 factor app. Not the end of the world, but not great.
They offer a fair number of pre-templated installation options for the linux container. Here is a docker-compose.yml that I'll probably wind up using for my demo setup.
version: '3'
services:
db:
octopus-server:
...
Packaging
Next, they discuss 'packaging':
Before you can deploy software with Octopus Deploy, you need to bundle all the files required for the software to run in a supported package. The package must be versioned and stored in a repository. Octopus Deploy includes a built-in repository
Let's see how laborious this packaging system is! They support enough packaging types that it would never get in my way personally:
Because I would deploy Docker containers, I started there and found this page which details how to do that. It's interesting to me that Octopus started as a .NET
first system and only later added support for Docker.
Here is the .NET
deploy procedure:
I'm not intimate with .NET
but I do wonder how you define how to execute the package once it's extracted.
This is the Docker
deploy procdure:
It seems fine, I wondered how to add a runtime variable and eventually found it:
You're expected to interact with this mostly through the Web GUI which is fine. No rocket science here, which is good this shouldn't be overcomplicated.
Infrastructure
The Vendor Portal includes a page for managing infrastructure that you want to deploy to. This is where the rubber meets the road if you will. They support many different target types, which seems like it would cover almost anywhere you would reasonably want to deploy to.
With Octopus Deploy, you can deploy software to Windows servers, Linux servers, Microsoft Azure, AWS, Kubernetes clusters, cloud regions, or an offline package drop. Regardless of where you’re deploying your software, these machines and services known as your deployment targets.
I'm not interested in the cloud provider integrations. I am interested in learning about the Tentacle
agents and offline drops
.
Tentacle
The tentacle is essentially a C&C
agent, constantly checking for instructions from the Command Server (Octopus Deploy Portal). When it receives an instruction it's executed and the result is sent back over the wire.
You can configure it as a listener (I.E. Open a port on the customer network) or as a polling server where it will constantly reach out looking for instruction.
While having the listener makes sense from a performance perspective, I can't imaging many customers would want to set that up. Imagine the response from ITSec when a team asks "Hey we're buying this piece of software, they need to setup a port on a VM so they can deploy updates whenever they want into our network!".
Imagine if Octopus is breached, it would be like SolarWinds, Yikes.
Regardless of this, of customers are willing to adopt it I bet it opens a lot of very useful features for the vendor.
SSH Targets
This is neat too, how do they handle this?
When using SSH for deployments to a Linux server, the Tentacle agent is not required and doesn’t need to be installed.
They do recommend against using this and suggest the Tentacle approach.
The Requirements:
The actions are apparently executed with 'Calamari', which must be something like Ansible? Perhaps they install that over SSH? I would like to see more details about what they are actually executing on the host. Maybe I'll do some testing of this later.
Offline Drop
I was pretty excited about a novel approach here, but honestly I was a little disappointed by the simplicity of the approach, detailed here. It compresses everything you need to run your app, and defines a boot script that is executed when it's unpacked.
I'll definitely have to try this out, too.
Demo and Architecture Investigation
Going through the landing page, I can choose cloud or self-hosted.
Self-hosted has a free tier that is quite permissive. Today I'll be trying that out.
This brings you to a sign-in page.
After you sign in, you're asked where you want to deploy. Funny enough they limit to 5 trials per Email domain and that includes public domains. I'm probably lucky to be able to use this email.
After this screen, it loads information about the license. The free trial is 30 days. There's no clear guidance on what to do next, I clicked everything in the dashboard and all it discusses are licenses.
RTFM; I hit the docs. From the getting started, the first step is deploying Octopus Deploy
.
Step 1 - Deploying 'Octopus Deploy Server'
Following the installation manual, you can either run this as a Windows service or as a Container. I do not want to spin up a Windows Server VM, so I'll setup a linux instance and setup Docker to run it that way. There're no details on requirements so I guessed.
Once installation was complete, I cloned the VM so I have two to work from:
On the deploy-server
:
$ # Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Add the repository to Apt sources:
echo \
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
\"$(. /etc/os-release && echo \"$VERSION_CODENAME\")\" stable\" | \\
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
$ sudo apt install docker-ce docker-ce-cli docker-compose-plugin docker-compose
$ mkdir octopus
$ cd octopus
$ vim docker-compose.yml
### Wrote compose file from above ###
version: '3'
services:
db:
image: ${SQL_IMAGE}
environment:
SA_PASSWORD: ${SA_PASSWORD}
ACCEPT_EULA: ${ACCEPT_EULA}
ports:
- 1401:1433
healthcheck:
test: [ "CMD", "/opt/mssql-tools/bin/sqlcmd", "-U", "sa", "-P", "${SA_PASSWORD}", "-Q", "select 1"]
interval: 10s
retries: 10
volumes:
- sqlvolume:/var/opt/mssql
octopus-server:
image: octopusdeploy/octopusdeploy:${OCTOPUS_SERVER_TAG}
privileged: ${PRIVILEGED}
user: ${CONTAINER_USER}
environment:
ACCEPT_EULA: ${ACCEPT_OCTOPUS_EULA}
OCTOPUS_SERVER_NODE_NAME: ${OCTOPUS_SERVER_NODE_NAME}
DB_CONNECTION_STRING: ${DB_CONNECTION_STRING}
ADMIN_USERNAME: ${ADMIN_USERNAME}
ADMIN_PASSWORD: ${ADMIN_PASSWORD}
ADMIN_EMAIL: ${ADMIN_EMAIL}
OCTOPUS_SERVER_BASE64_LICENSE: ${OCTOPUS_SERVER_BASE64_LICENSE}
MASTER_KEY: ${MASTER_KEY}
ADMIN_API_KEY: ${ADMIN_API_KEY}
DISABLE_DIND: ${DISABLE_DIND}
ports:
- 8080:8080
- 11111:10943
depends_on:
- db
volumes:
- repository:/repository
- artifacts:/artifacts
- taskLogs:/taskLogs
- cache:/cache
- import:/import
- eventExports:/eventExports
volumes:
repository:
artifacts:
taskLogs:
cache:
import:
eventExports:
sqlvolume:
### End ###
$ vim .env
### Write ###
# Define the password for the SQL database. This also must be set in the DB_CONNECTION_STRING value.
SA_PASSWORD=
# Tag for the Octopus Deploy Server image. Use "latest" to pull the latest image or specify a specific tag
OCTOPUS_SERVER_TAG=latest
# Sql Server image. Set this variable to the version you wish to use. Default is to use the latest.
SQL_IMAGE=mcr.microsoft.com/mssql/server
# The default created user username for login to the Octopus Server
ADMIN_USERNAME=
# It is highly recommended this value is changed as it's the default user password for login to the Octopus Server
ADMIN_PASSWORD=
# Email associated with the default created user. If empty will default to octopus@example.local
ADMIN_EMAIL=
# Accept the Microsoft Sql Server Eula found here: https://go.microsoft.com/fwlink/?linkid=857698
ACCEPT_EULA=Y
# Use of this Image means you must accept the Octopus Deploy Eula found here: https://octopus.com/company/legal
ACCEPT_OCTOPUS_EULA=Y
# Unique Server Node Name - If left empty will default to the machine Name
OCTOPUS_SERVER_NODE_NAME=
# Database Connection String. If using database in sql server container, it is highly recommended to change the password.
DB_CONNECTION_STRING=Server=db,1433;Database=OctopusDeploy;User=sa;Password=THE_SA_PASSWORD_DEFINED_ABOVE
# Your License key for Octopus Deploy. If left empty, it will try and create a free license key for you
OCTOPUS_SERVER_BASE64_LICENSE=
# Octopus Deploy uses a master key for encryption of your databse. If you're using an external database that's already been setup for Octopus Deploy,
# you can supply the master key to use it.
# If left blank, a new master key will be generated with the database creation.
# Create a new master key with the command: openssl rand 16 | base64
MASTER_KEY=
# The API Key to set for the administrator. If this is set and no password is provided then a service account user will be created.
# If this is set and a password is also set then a standard user will be created.
#
ADMIN_API_KEY=
# Docker-In-Docker is used to support worker container images. It can be disabled by setting DISABLE_DIND to Y.
# The container only requires the privileged setting if DISABLE_DIND is set to N.
DISABLE_DIND=Y
PRIVILEGED=false
# Octopus can be run either as the user root or as octopus.
CONTAINER_USER=octopus
### END ###
# Store value of this command in `MASTER_KEY` value of the .env file
$ openssl rand 16 | base64
# Deploy
$ docker-compose --project-name Octopus up -d
Creating network "octopus_default" with the default driver
Creating volume "octopus_repository" with default driver
Creating volume "octopus_artifacts" with default driver
Creating volume "octopus_taskLogs" with default driver
Creating volume "octopus_cache" with default driver
Creating volume "octopus_import" with default driver
Creating volume "octopus_eventExports" with default driver
Creating volume "octopus_sqlvolume" with default driver
Pulling db (mcr.microsoft.com/mssql/server:)...
latest: Pulling from mssql/server
5b07ce5bcac1: Pull complete
...
Digest: sha256:5362c818aad4a787e3bac20d19a2e8db7ac91cdc30b359c176bc986547b0c2d0
Status: Downloaded newer image for mcr.microsoft.com/mssql/server:latest
Pulling octopus-server (octopusdeploy/octopusdeploy:latest)...
latest: Pulling from octopusdeploy/octopusdeploy
7d97e254a046: Pull complete
...
Digest: sha256:65c820a7f55fe8ac4d83c6571d871f6ad73ee65bfc8451de12d4d878102cc2c8
Status: Downloaded newer image for octopusdeploy/octopusdeploy:latest
Creating octopus_db_1 ... done
Creating octopus_octopus-server_1 ... done
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
$ docker-compose ps
Name Command State Ports
----------------------------------------------------------------------------
octopus_db_1 /opt/mssql/bin/permissions ... Exit 255
octopus_octopus-server_1 ./install.sh Exit 100
Oh my, it didn't work.
$ docker-compose logs
...
ERROR: Unable to set system administrator password: Password validation failed. The password does not meet SQL Server password policy requirements because it is not complex enough. The password must be at least 8 characters long and contain characters from three of the following four sets: Uppercase letters, Lowercase letters, Base 10 digits, and Symbols..
...
Well the docs didn't mention that! I modified the .env
to create a more complex password, cleaned everything up and launched again.
$ docker-compose stop && docker-compose rm
$ docker volume prune -a
$ docker-compose --project-name Octopus up -d
Recreating octopus_db_1 ... done
Recreating octopus_octopus-server_1 ... done
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS
PORTS NAMES
b936311543eb octopusdeploy/octopusdeploy:latest "./install.sh " 5 seconds ago Up 3 seconds (health: starting) 443/tcp, 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp, 0.0.0.0:11111->10943/tcp, :::11111->10943/tcp octopus_octopus-server_1
5763db9aace0 mcr.microsoft.com/mssql/server "/opt/mssql/bin/perm…" 7 seconds ago Up 5 seconds (health: starting) 0.0.0.0:1401->1433/tcp, :::1401->1433/tcp
I loaded port 8080
in a browser:
Step 2 - Create a Project & Process
The GUI seems well designed and guides you through the process of getting started nicely. First you create a project
.
A project defines your whole application stack
They have you set your environment configuration for promoting a release.
Then you have to create the deployment process. I suppose I'll make a process to run a docker container on the target. It does look like there're a ton of job steps here available. This is building a CICD pipeline through the GUI.
The form for creating a docker container is quite long.
The tool tips are actually quite useful.
Looks like I have to go setup a docker registry first
Clicking the external feeds
link brought me here:
These are the available feed types:
The defaults create access to the public docker.io
registry. After creating it, a list displays it.
I clicked test and looked up nginx
I went back to the Process Editor
and clicked refresh, the registry was there but it looks like I need to specifically track an image.
I couldn't figure out what to set as 'package ID', so I hit the docs.
Package IDs must conform to the following specifications:
Package IDs must be unique within your Octopus Deploy instance. Package IDs consist of one or more segments separated by one of the following separator characters: - . _. Segments contain only alphanumeric characters.
For instance, the package ID in this sample package is hello-world.
hello-world.1.0.0.zip
Avoid using numbers in your package ID as it could result in the version number being incorrectly parsed.
There's a specific page for packaging a public image. You set the package ID as the image name and it'll show you available versions.
Turns out the UX there is really nice. When you start typing the Packer ID
it performs a search against the registry and displays available repositories.
I chose the mainline nginx
repo. I left defaults for network except I let it map the default port to host, which should bind to 80
.
No volumes:
No variables for now:
They have other useful execution fields, the don't auto-run
is nice to have, a lot of times you have to mess with the boot order of the container yourself and most systems make that difficult.
Finally you can configure the behaviour of the step in the CD process.
I saved.
Step 3 - Add Deployment Target
Now I need somewhere to actually deploy to. I said I would setup their agent on a linux VM. When you click 'Infrastructure' this page is displayed:
I went through 'Add Deployment Target'
I feel like Polling
is the most realistic for on-prem so I'll do that.
Alright so I have to install the agent on my other VM. They have a deb
package for Debian so I'll use that.
$ apt-key adv --fetch-keys https://apt.octopus.com/public.key
$ add-apt-repository "deb https://apt.octopus.com/ stretch main"
$ apt update && apt install tentacle
Then they have a shell script to configure it:
$ /opt/octopus/tentacle/configure-tentacle.sh
Name of Tentacle instance (default Tentacle):demo-target
What kind of Tentacle would you like to configure: 1) Listening or 2) Polling (default 1): 2
Where would you like Tentacle to store log files? (/etc/octopus):
Where would you like Tentacle to install applications to? (/home/Octopus/Applications):
Octopus Server URL (eg. https://octopus-server): http://10.10.0.25:8080
Select auth method: 1) API-Key or 2) Username and Password (default 1): 1
API-Key:
Looks like I need an API key. It was easy to find under account profile in the portal:
Select type of Tentacle do you want to setup: 1) Deployment Target or 2) Worker (default 1): 1
What Space would you like to register this Tentacle in? (Default):
What name would you like to register this Tentacle with? (octoopus-demo-target):
Enter the environments for this Tentacle (comma seperated): Development
Enter the roles for this Tentacle (comma seperated): web-server
The following configuration commands will be run to configure Tentacle:
sudo /opt/octopus/tentacle/Tentacle create-instance --instance "demo-target" --config "/etc/octopus/demo-target/tentacle-demo-target.config"
sudo /opt/octopus/tentacle/Tentacle new-certificate --instance "demo-target" --if-blank
sudo /opt/octopus/tentacle/Tentacle configure --instance "demo-target" --app "/home/Octopus/Applications" --noListen "True" --reset-trust
sudo /opt/octopus/tentacle/Tentacle register-with --instance "demo-target" --server "http://10.10.0.25:8080" --name "octoopus-demo-target" --comms-style "TentacleActive" --server-comms-port "10943" --apiKey "API-XXXXXXXXXXXXXXXXXXXXXXXXXX" --space "Default" --environment "Development" --role "web-server"
sudo /opt/octopus/tentacle/Tentacle service --install --start --instance "demo-target"
...
Connection refused [::ffff:10.10.0.25]:10943
Looking at the containers running on the server, the docker-compose script binds 11111
to 10943
. Because the string you set during their installer doesn't affect the --comms-port
flag, I changed it in the compose script instead.
With that change completed I tried again, and got the same error. The port is open on the server and can be reached from the target. I fiddled with this for a while but didn't figure it out.
# On Server
$ nc localhost 10943 -v
Connection to localhost 10943 port [tcp/*] succeeded!
# On Target
$ nc 10.10.0.25 10943 -v
Connection to 10.10.0.25 10943 port [tcp/*] succeeded!
I have up and decided to try the default/suggested route of setting up a listener on the server. In my opinion this would be difficult to do in a real environment, I can't see customer IT being happy about opening a port to the world.
$ /opt/octopus/tentacle/configure-tentacle.sh
Name of Tentacle instance (default Tentacle):demo-target
What kind of Tentacle would you like to configure: 1) Listening or 2) Polling (default 1):
Where would you like Tentacle to store log files? (/etc/octopus):
Where would you like Tentacle to install applications to? (/home/Octopus/Applications):
Enter the port that this Tentacle will listen on (10933):
Enter the thumbprint of the Octopus Server: 927261E584BAFB96D3CFAF496F3D09C562D95896
The following configuration commands will be run to configure Tentacle:
sudo /opt/octopus/tentacle/Tentacle create-instance --instance "demo-target" --config "/etc/octopus/demo-target/tentacle-demo-target.config"
sudo /opt/octopus/tentacle/Tentacle new-certificate --instance "demo-target" --if-blank
sudo /opt/octopus/tentacle/Tentacle configure --instance "demo-target" --app "/home/Octopus/Applications" --port 10933 --noListen False --reset-trust
sudo /opt/octopus/tentacle/Tentacle configure --instance "demo-target" --trust 927261E584BAFB96D3CFAF496F3D09C562D95896
sudo /opt/octopus/tentacle/Tentacle service --install --start --instance "demo-target"
Press enter to continue...
Configuration file at /etc/octopus/demo-target/tentacle-demo-target.config already exists.
Setting home directory to: /etc/octopus/demo-target
Saving instance: demo-target
A certificate already exists, no changes will be applied.
Removing all trusted Octopus Servers...
Application directory set to: /home/Octopus/Applications
Services listen port: 10933
Tentacle will listen on a TCP port
These changes require a restart of the Tentacle.
Adding 1 trusted Octopus Servers
These changes require a restart of the Tentacle.
Service installed: demo-target
Service started: demo-target
Tentacle instance 'demo-target' is now installed
This route was straight-forward though and installed almost instantly.
You then set the remaining settings in the GUI:
It seems to have worked without any errors
This is confirmed with a connectivity check tab:
Step 4 - Deploy to Target
To deploy, you create a 'release'. When opening this pane I was warned that I needed credentials now for docker.io
,so I set that up.
Now I can create the release:
It provides a summary, and the ability to deploy to Development:
Clicking deploy gives you a confirmation window:
This then brings up a dynamic page that is showing the progress of the deployment:
But, it failed.
There're more details logs in the form of what seems like a stack trace?
Ah okay, so I actually need to add an 'Install Docker' job to this deployment process! There's already a communitity maintained step for installing Docker, but it took me a while to figure out how to massage the GUI into changing the order of the steps. Drag and drop would be nice here but I did figure it out after 5 minutes or so.
Then I hit re-try on the deployment:
Which was folly of me...
I have to create a new release, which also failed:
Maybe un-nesting the steps will help? Perhaps nested steps are executed in parallel or something.
I don't know why exactly, but that actually worked.
Now I tried accessing the server IP at port 80, and nothing is listening there. I dug around the UI forever and couldn't figure out what the port mapping was.
There's a script console
where I was able to run docker ps
through the GUI.
I can see that it chose to map 32768 to port 80. My understanding was it would map 80->80 but that's okay. Here it is!
Step 5 - Demo Runbooks
It's the same component as creating a deployment job, so this is how you automate deployments or other processes in the framework.
Nice and easy!
Summary
Octopus does a fantastic job at providing great user experience. Their web application is top-tier with helpful information everywhere you need it and nice responsive pages that make everything feel nice.
Their architecture is essentially like a command and control server. Like seriously, it has all the features a bad-actor would want!
I would be comfortable using this tool in two scenarios:
- I'm running the Octopus Deploy server on-prem, listeners are configured on my cloud resources to take actions across providers
- I'm running everything on-prem
I would not want to use their cloud solution to connect to resources on-prem, due to how the connections are established. I also thought they had some more complex proxy functionality, but it really is the ability to connect through an existing proxy.
The Runbooks were also a little disappointing for some reason, It does exactly what it says it does, I don't know what I was expecting but I thought it would be different than the Deploy process. In reality, triggered or scheduled 'Processes' is exactly what it needs to be.
The Process editor was quite good, there's no way it's not faster than writing CICD manifests manually.