Have Sail and SSU. Runs a command on a remote host.

This commit is contained in:
Joao Patricio 2023-03-20 14:04:35 +00:00
parent a613e9f113
commit bfdae4339c
15 changed files with 234 additions and 77 deletions

View File

@ -8,6 +8,7 @@ GROUPID=
############################################################################################################
APP_NAME=Laravel
APP_SERVICE=php
APP_ENV=local
APP_KEY=
APP_DEBUG=true
@ -17,7 +18,7 @@ DB_CONNECTION=pgsql
DB_HOST=postgres
DB_PORT=5432
DB_DATABASE=coolify
DB_USERNAME=sail
DB_USERNAME=coolify
DB_PASSWORD=password
QUEUE_CONNECTION=redis
QUEUE_CONNECTION=database

View File

@ -12,7 +12,7 @@ class RunCommand extends Component
public $manualKeepAlive = false;
public $command = '';
public $command = 'ls';
public function render()
{
@ -21,30 +21,32 @@ public function render()
public function runCommand()
{
// TODO Execute with Livewire Normally
$this->activity = coolifyProcess($this->command, 'testing-host');
$this->isKeepAliveOn = true;
// Override manual to experiment
// $sleepingBeauty = 'x=1; while [ $x -le 40 ]; do sleep 0.1 && echo "Welcome $x times" $(( x++ )); done';
//
// $commandString = <<<EOT
// cd projects/dummy-project
// ~/.docker/cli-plugins/docker-compose build --no-cache
// # $sleepingBeauty
// EOT;
//
// $this->activity = coolifyProcess($commandString, 'testing-host');
$override = 0;
if($override) {
// Good to play with the throttle feature
$sleepingBeauty = 'x=1; while [ $x -le 40 ]; do sleep 0.1 && echo "Welcome $x times" $(( x++ )); done';
$this->isKeepAliveOn = true;
$this->activity = coolifyProcess(<<<EOT
cd projects/dummy-project
# ~/.docker/cli-plugins/docker-compose build --no-cache
$sleepingBeauty
EOT, 'testing-host');
return;
}
$this->activity = coolifyProcess($this->command, 'testing-host');
}
public function polling()
{
$this->activity?->refresh();
if ($this->activity?->properties['status'] === 'finished') {
if (data_get($this->activity, 'properties.exitCode') !== null) {
$this->isKeepAliveOn = false;
}
}

View File

@ -2,6 +2,7 @@
namespace App\Jobs;
use App\Services\ProcessStatus;
use Illuminate\Support\Facades\DB;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
@ -11,7 +12,6 @@
use Illuminate\Process\ProcessResult;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Process;
use Spatie\Activitylog\Contracts\Activity;
@ -43,8 +43,7 @@ public function __construct(
*/
public function handle(): ?ProcessResult
{
ray()->clearAll();
$this->timeStart = $start = hrtime(true);
$this->timeStart = hrtime(true);
$user = $this->activity->getExtraProperty('user');
$destination = $this->activity->getExtraProperty('destination');
@ -53,24 +52,16 @@ public function handle(): ?ProcessResult
$delimiter = 'EOF-COOLIFY-SSH';
File::chmod(base_path('coolify_id25519'), 0600);
$sshCommand = 'ssh '
. '-i ./coolify_id25519 '
. '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null '
. '-o PasswordAuthentication=no '
. "-p {$port} "
. "{$user}@{$destination} "
. " 'bash -se' << \\$delimiter" . PHP_EOL
. $command . PHP_EOL
. $delimiter;
// $sshCommand = "whoami ; pwd ; ls ";
$process = Process::start(
$sshCommand,
$this->handleOutput(...),
);
$process = Process::start($sshCommand, $this->handleOutput(...));
$res = $process->wait();
@ -78,13 +69,20 @@ public function handle(): ?ProcessResult
return $res;
}
$status = match ($res->exitCode()) {
0 => ProcessStatus::FINISHED,
default => ProcessStatus::ERROR,
};
$this->activity->properties = $this->activity->properties->merge([
'exitCode' => $res->exitCode(),
'stdout' => $res->output(),
'stderr' => $res->errorOutput(),
'status' => $status,
]);
// TODO Why is this not persisting?? Immutable property??
$this->activity->properties->put('pid', $process->id());
$this->activity->properties->put('exitCode', $res->exitCode());
$this->activity->properties->put('stdout', $res->output());
$this->activity->properties->put('stderr', $res->errorOutput());
$this->activity->save();
return $res;
}

View File

@ -19,12 +19,14 @@ public function __construct(
protected ?string $user = 'root',
){
$this->activity = activity()
->withProperty('type', 'COOLIFY_PROCESS')
->withProperty('user', $this->user)
->withProperty('destination', $this->destination)
->withProperty('port', $this->port)
->withProperty('command', $this->command)
->withProperty('status', ProcessStatus::HOLDING)
->withProperties([
'type' => 'COOLIFY_PROCESS',
'user' => $this->user,
'destination' => $this->destination,
'port' => $this->port,
'command' => $this->command,
'status' => ProcessStatus::HOLDING,
])
->log("Awaiting to start command...\n\n");
}

View File

@ -1,7 +0,0 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevAAAAJi/QySHv0Mk
hwAAAAtzc2gtZWQyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevA
AAAECBQw4jg1WRT2IGHMncCiZhURCts2s24HoDS0thHnnRKVuGmoeGq/pojrsyP1pszcNV
uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
-----END OPENSSH PRIVATE KEY-----

View File

@ -3,15 +3,18 @@ services:
php:
image: coolify:4
build:
dockerfile: Dockerfile
context: ./docker/dev
dockerfile: Dockerfile
args:
WWWGROUP: '${WWWGROUP}'
ports:
- "${APP_PORT:-8000}:80"
- "${VITE_PORT:-5173}:${VITE_PORT:-5173}"
environment:
PUID: "${USERID:-9999}"
PGID: "${GROUPID:-9999}"
SSL_MODE: 'off'
WWWUSER: "${WWWUSER}"
LARAVEL_SAIL: 1
XDEBUG_MODE: "${SAIL_XDEBUG_MODE:-off}"
XDEBUG_CONFIG: "${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}"
volumes:
- .:/var/www/html
networks:

View File

@ -1,20 +1,93 @@
FROM serversideup/php:8.2-fpm-nginx
FROM ubuntu:22.04
ARG WWWGROUP
ARG TARGETPLATFORM
ARG NODE_VERSION=18
ARG POSTGRES_VERSION=15
ARG POSTGRES_VERSION=14
# https://download.docker.com/linux/static/stable/
ARG DOCKER_VERSION=20.10.18
# https://github.com/docker/compose/releases
# Reverted to 2.6.1 because of this https://github.com/docker/compose/issues/9704. 2.9.0 still has a bug.
ARG DOCKER_COMPOSE_VERSION=2.6.1
# https://github.com/buildpacks/pack/releases
ARG PACK_VERSION=v0.27.0
WORKDIR /var/www/html
ENV DEBIAN_FRONTEND noninteractive
ENV TZ=UTC
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN apt-get update \
&& apt-get install -y gnupg gosu curl ca-certificates zip unzip git git-lfs supervisor sqlite3 libcap2-bin libpng-dev python2 dnsutils \
&& curl -sS 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x14aa40ec0831756756d7f66c4f4ea0aae5267a6c' | gpg --dearmor | tee /usr/share/keyrings/ppa_ondrej_php.gpg > /dev/null \
&& echo "deb [signed-by=/usr/share/keyrings/ppa_ondrej_php.gpg] https://ppa.launchpadcontent.net/ondrej/php/ubuntu jammy main" > /etc/apt/sources.list.d/ppa_ondrej_php.list \
&& apt-get update \
&& apt-get install -y php8.2-cli php8.2-dev \
php8.2-pgsql php8.2-sqlite3 php8.2-gd \
php8.2-curl \
php8.2-imap php8.2-mysql php8.2-mbstring \
php8.2-xml php8.2-zip php8.2-bcmath php8.2-soap \
php8.2-intl php8.2-readline \
php8.2-ldap \
php8.2-msgpack php8.2-igbinary php8.2-redis php8.2-swoole \
php8.2-memcached php8.2-pcov php8.2-xdebug \
&& php -r "readfile('https://getcomposer.org/installer');" | php -- --install-dir=/usr/bin/ --filename=composer \
&& curl -sLS https://deb.nodesource.com/setup_$NODE_VERSION.x | bash - \
&& apt-get install -y nodejs \
&& npm install -g npm
RUN apt-get install -y php-pgsql openssh-client
RUN apt-get -y autoremove \
&& npm install -g npm \
&& curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor | tee /usr/share/keyrings/yarn.gpg >/dev/null \
&& echo "deb [signed-by=/usr/share/keyrings/yarn.gpg] https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list \
&& curl -sS https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /usr/share/keyrings/pgdg.gpg >/dev/null \
&& echo "deb [signed-by=/usr/share/keyrings/pgdg.gpg] http://apt.postgresql.org/pub/repos/apt jammy-pgdg main" > /etc/apt/sources.list.d/pgdg.list \
&& apt-get update \
&& apt-get install -y yarn \
&& apt-get install -y mysql-client \
&& apt-get install -y postgresql-client-$POSTGRES_VERSION \
&& apt-get -y autoremove \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/*
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN setcap "cap_net_bind_service=+ep" /usr/bin/php8.2
RUN groupadd --force -g $WWWGROUP sail
RUN useradd -ms /bin/bash --no-user-group -g $WWWGROUP -u 1337 sail
USER sail
RUN mkdir -p ~/.ssh
RUN echo "-----BEGIN OPENSSH PRIVATE KEY-----\n\
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\n\
QyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevAAAAJi/QySHv0Mk\n\
hwAAAAtzc2gtZWQyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevA\n\
AAAECBQw4jg1WRT2IGHMncCiZhURCts2s24HoDS0thHnnRKVuGmoeGq/pojrsyP1pszcNV\n\
uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==\n\
-----END OPENSSH PRIVATE KEY-----" >> ~/.ssh/id_ed25519
RUN chmod 0600 ~/.ssh/id_ed25519
USER root
# S6 Overlay config
COPY --chmod=755 etc/s6-overlay/ /etc/s6-overlay/
COPY start-container /usr/local/bin/start-container
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
COPY php.ini /etc/php/8.2/cli/conf.d/99-sail.ini
RUN chmod +x /usr/local/bin/start-container
# Install Docker CLI, Docker Compose, and Pack
RUN mkdir -p ~/.docker/cli-plugins
RUN curl -SL https://cdn.coollabs.io/bin/$TARGETPLATFORM/docker-$DOCKER_VERSION -o /usr/bin/docker
RUN curl -SL https://cdn.coollabs.io/bin/$TARGETPLATFORM/docker-compose-linux-$DOCKER_COMPOSE_VERSION -o ~/.docker/cli-plugins/docker-compose -o /home/sail/.docker/cli-plugins/docker-compose
RUN curl -SL https://cdn.coollabs.io/bin/$TARGETPLATFORM/pack-$PACK_VERSION -o /usr/local/bin/pack
RUN curl -sSL https://nixpacks.com/install.sh | bash
RUN chmod +x ~/.docker/cli-plugins/docker-compose /usr/bin/docker /usr/local/bin/pack
RUN chmod +x /usr/local/bin/pack
RUN mkdir -p /home/sail/.docker/cli-plugins
RUN cp ~/.docker/cli-plugins/docker-compose /home/sail/.docker/cli-plugins/docker-compose
RUN chown -R sail:sail /home/sail
EXPOSE 8000
ENTRYPOINT ["start-container"]

4
docker/dev/php.ini Normal file
View File

@ -0,0 +1,4 @@
[PHP]
post_max_size = 100M
upload_max_filesize = 100M
variables_order = EGPCS

View File

@ -0,0 +1,17 @@
#!/usr/bin/env bash
if [ ! -z "$WWWUSER" ]; then
usermod -u $WWWUSER sail
fi
if [ ! -d /.composer ]; then
mkdir /.composer
fi
chmod -R ugo+rw /.composer
if [ $# -gt 0 ]; then
exec gosu $WWWUSER "$@"
else
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
fi

View File

@ -0,0 +1,27 @@
[supervisord]
nodaemon=true
user=root
logfile=/var/log/supervisor/supervisord.log
pidfile=/var/run/supervisord.pid
[program:php]
command=/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan serve --host=0.0.0.0 --port=80
user=sail
environment=LARAVEL_SAIL="1"
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan queue:listen
user=sail
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
numprocs=8
redirect_stderr=true
stdout_logfile=/var/www/html/storage/logs/worker.log
stopwaitsecs=3600

20
docker/staging/Dockerfile Normal file
View File

@ -0,0 +1,20 @@
FROM serversideup/php:8.2-fpm-nginx
ARG NODE_VERSION=18
ARG POSTGRES_VERSION=15
RUN apt-get update \
&& curl -sLS https://deb.nodesource.com/setup_$NODE_VERSION.x | bash - \
&& apt-get install -y nodejs \
&& npm install -g npm
RUN apt-get install -y php-pgsql openssh-client
RUN apt-get -y autoremove \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/*
USER root
# S6 Overlay config
COPY --chmod=755 etc/s6-overlay/ /etc/s6-overlay/

View File

@ -6,7 +6,7 @@
</label>
<button class="btn btn-success btn-xs rounded-none" wire:click="runCommand">
Run command
<button>
<button>
</div>
@isset($activity?->id)
@ -18,6 +18,35 @@
<div class="w-full h-10"></div>
<div
@if($isKeepAliveOn || $manualKeepAlive) wire:poll.750ms="polling" @endif
>
<pre
style="
background-color: #FFFFFF;
width: 1200px;
height: 600px;
overflow-y: scroll;
display: flex;
flex-direction: column-reverse;
"
placeholder="Build output"
>
{{ data_get($activity, 'description') }}
</pre>
<div>
<input id="manualKeepAlive" name="manualKeepAlive" type="checkbox" wire:model="manualKeepAlive">
<label for="manualKeepAlive"> Live content </label>
</div>
@if($isKeepAliveOn || $manualKeepAlive)
Polling...
@endif
</div>
<pre
style="
background-color: #FFFFFF;
@ -28,17 +57,5 @@
flex-direction: column-reverse;
"
placeholder="Build output"
@if($isKeepAliveOn || $manualKeepAlive) wire:poll.750ms="polling" @endif
>
{{ data_get($activity, 'description') }}
</pre>
<div>
<input id="manualKeepAlive" name="manualKeepAlive" type="checkbox" wire:model="manualKeepAlive">
<label for="manualKeepAlive"> Live content </label>
</div>
@if($isKeepAliveOn || $manualKeepAlive)
Polling...
@endif
>{{ json_encode(data_get($activity, 'properties'), JSON_PRETTY_PRINT) }}</pre>
</div>