CLI script

From Cloudrexx Development Wiki
Jump to: navigation, search

This page is about the Cloudrexx CLI script (./cx). It focuses on technical "nice to know"s.

Structure

The script is divided into three parts: Windows, Unix and PHP:

Bash 3 / Bash 4

The script requires Bash version 4. In order for the script to run on Bash 3 (which is default on MacOS) we route all calls through a wrapping container (docker image cloudrexx/ubuntu). This is only done for Bash 3. Calls on Bash 4 and newer are executed directly.

In order to allow the cx script inside the wrapping Ubuntu container to control Docker on the host system the Docker socket is mounted to that container. This works nicely and allows to control Docker from inside the container. However, Docker Compose has an issue when mounting the current directory using ".": If run from inside the container, it tries to mount the container's current directory. In order to circumvent that, the script passes the argument --proxy-host-dir=<cd> to all calls of cx. This way the script running in the container knows the directory on the host and can change the docker-compose.yml accordingly. The same can be achieved by setting the environment variable PROXY_HOST_DIR which is used for when calling ./cx env shell --wrapper.

Windows / Unix

Using the same script for Unix and Windows is achieved by using the following scheme:

@GOTO WIN \
2>/dev/null

# Unix part

exit
:WIN

REM Batch script

The first two lines instruct Windows to jump to the marker WIN and bash to route the error message that @GOTO WIN is not a valid command to /dev/null. The only issue with this is that the file can not start with a shebang, as Windows would throw an error on that.

The Windows part (batch script) is a simplistic wrapper to call the Unix part in a Docker container running Ubuntu. It checks if a file named cx is available in the current directory. If not, it instructs the Ubuntu container to download it. After that it calls ./cx inside the Ubuntu container with all arguments you passed to it on Windows.

The wrapping mechanism is the same as for Bash version 3.

Bash / PHP

The Unix part contains some internal commands. For all other calls the Unix part is a simple wrapper to call php index.php in the correct Docker container. If the container is not available, it tries to use the PHP executable on the host (if any). For the PHP part see Command Mode.

Internal Commands

env

This command manages an environment. There are two different types of environments: vhost and standalone.

Standalone Environments

In standalone environments the web-container's port on which it accepts connections is directly bound to the hosts port. Therefore there can only be one standalone environment per not-yet-occupied port on your system.

Vhost Environments

Vhost environments are all on the same port. In order for this to work, there needs to be a proxy container running. For more info see envs command

Subcommand description

Subcommand Description
init Performs the following (in this order):
  • Checks out the repositories (and sets "assume-unchanged" for tmp/* and config/*)
  • Internally calls env config to configure the environment
  • Sets the CONTREXX_INSTALLED constant to true
  • Internally calls env up to start the docker containers
  • Internally calls env update --db --drop-users to initialize the database
  • Auto-configures caching for versions 5 and newer
config Allows to automatically or manually configure the environment as well as displaying the current configuration. The configuration is saved in config/settings.php, config/configuration.php and docker-compose.yml. _meta/docker-compose.tpl is used as a template for docker-compose.yml
up Calls docker-compose --project-name <name> up -d and waits for the database server to be ready. <name> is set to your hostname without the dots, prefixed by clxenv.
down Calls docker-compose --project-name <name> down. The -v flag is added to that call if --purge is specified.
restart Internally calls down and up
update Updates both repositories and reloads the database if necessary. You can use --db to only do a database reload
status Shows the status of the docker containers associated with the current environment by calling docker-compose --project-name <name> ps
info Internally calls status and config --show
shell Opens an interactive bash shell to the web container

Automatic configuration

Automatically, the following presets are set:

Contrexx/Cloudrexx version PHP version Database image PHP image Cache Other
Cloudrexx 5 and newer 7.4 mariadb:10.5 cloudrexx/web:PHP<php-version>-with-mysql All caches active
Contrexx 3-4 5.6 mariadb:5 Inactive Ports other than 80 are not supported
Contrexx 1-2 5.3


Known issues

  • The port for phpMyAdmin cannot be changed. Therefore the initialization of a second (non-vhost-) environment (even if on another port) fails.
  • On Windows you might encounter some permission problems. This is a known limitation to Docker on Windows [1]

See Missing things / Enhancement ideas for a complete list.

envs

This command manages Docker containers which are not specific to one environment. Currently this manages an NGINX proxy with docker-gen [2] which allows virtual hosting with no manual configuration. The proxy could be extended with automatically generated SSL certificates [3].

Subcommand description

Subcommand Description
up Starts the proxy
down Stops the proxy
restart Internally calls down and up
status Calls docker ps for the proxy container
info Calls docker ps with a filter to show all containers which are part of an environment
shell Opens an interactive shell on the proxy container
debug Shows logs from the NGINX proxy (wrapper for docker logs -f)
list Show a list of all environments that are up
find Shows the working directory of an environment

Make one ENV accessible from another computer

As the *.clx.dev domains always point to localhost, another computer won't be able to access your ENVs using such a domain. So in order to allow access from another computer you need to find some domain (or IP. For simplicity we simply say "domain" from now on, even if it might be an IP address.) that points the other computer to yours. Possible values are your computer's hostname or IP address. Depending on your network there might be more possibilities.

Once you have such a domain, do the following in the main directory of the ENV you want to make accessible:

./cx env down
# edit docker-compose.yml in your favorite editor
# look for the environment variable "VIRTUAL_HOST" in the first service ("web").
# add a comma (",", without a space) and your domain after the current value of "VIRTUAL_HOST"
# save (and close) the file
./cx env up

And there you go, your environment is now available on both of these domains. You can add as many domains as you want for each ENV (just don't use the same for multiple ENVs).

Note: you may need to disable Cloudrexx' domain enforcement in order to allow the other computer to navigate the site.

debug

By default this shows the last fatal error of the Cloudrexx installation (using the debug log file /tmp/log/dbg.log).

With --request only the last request's log (from /tmp/log/dbg.log) is shown (piped to less).

With --follow opens the log stream (of /tmp/log/dbg.log).

With --web shows the log of the web server (Apache) (continuously).

help

This command shows the help of all commands that are internally available. In addition it tries to call the help page via PHP and add the help from there to itself (basically listing the command mode commands). This can easily be seen when running this command twice: once with the environment up and once down.

Docker setup

Images

The Docker images used by cx are hosted on Docker Hub. The following list shows the PHP extensions available in the Docker images provided by Cloudrexx. The images are based on the official PHP images (if not stated otherwise). PHP extensions are listed by docker run --rm cloudrexx/web:PHP<php_version> php -r 'echo implode("\n", get_loaded_extensions()) . PHP_EOL;'

Extension PHP 5.3 [4] PHP 5.6 PHP 7.0 PHP 7.1 PHP 7.2-fpm PHP 7.3-fpm PHP 7.4-fpm PHP 8.0-fpm PHP 8.1-fpm
Core
date
ereg
libxml
openssl
pcre
sqlite3
zlib
ctype
curl
dom
fileinfo
filter
ftp
hash
iconv
json
mbstring
SPL
PDO
session
posix
readline
recode
Reflection
standard
SimpleXML
pdo_sqlite
Phar
tokenizer
xml
xmlreader
xmlwriter
mysqlnd
bcmath
exif
gd
intl
mcrypt
mysqli
pdo_mysql
zip
memcached
Zend OPcache
mysql
soap
SQLite
apc
igbinary
imagick
sockets

Additional installations

Xdebug

Use the following command to activate the PHP Xdebug extension in an environment. Please note that this is not a persistent change and will be dropped when you restart your environment.

./cx debug --install-x-debug

Composer

If you need composer in your container you can install it with the following one-liner:

./cx env exec --root "curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer"

After that you can call composer like this:

./cx env exec "composer --version"

NodeJS / NPM

If you need NodeJS/NPM in your container you can install it with the following one-liner:

./cx env exec --root "curl -sL https://deb.nodesource.com/setup_14.x | bash - && apt-get install -y nodejs"

After that you can call npm like this:

./cx env exec "npm -v"

strace

IMPORTANT: Due to security restrictions, strace can't be used by default in a Docker container. The following guide let's you disable certain security features of Docker to make strace working. You must never apply the following configuration on a production environment as it makes the container vulnerable to attacks.


To allow debugging a process using strace the web container has to be configured as follows:

First, ensure the container is not running:

./cx env down

Then, add the following options to docker-compose.yml:

security_opt:
- seccomp:unconfined
privileged: true

Example of modified docker-compose.yml file:

services:
  web:
    image: "cloudrexx/web:PHP5.6-with-mysql"
    hostname: "example.clx.dev
    ports:
      - "80:80"
    volumes:
      - .:/var/www/html
    depends_on:
      - db
      - usercache
    networks:
      - front-end
      - back-end
    security_opt:
      - seccomp:unconfined
    privileged: true

Start up the environment:

./cx env up

Install strace in the web container

./cx env exec --root "apt update && apt install strace"

Finally, strace is available for usage:

./cx env exec --root "strace -p <PID>"

HTTPS

HTTPS support is provided by the proxy container [5], but is not yet fully automated. In order to activate HTTPS support do the following:

  1. Create a directory for the certificates (i.e.: ~/ssl/).
  2. For each vhost you want to have HTTPS support, do add a private and public certificate key file. Save them in your certificate directory as <hostname>.key and <hostname>.crt.
    For self-signed certificates that are accepted by the browser, see https://alexanderzeitler.com/articles/Fixing-Chrome-missing_subjectAltName-selfsigned-cert-openssl/
    Note that you'll have to import the generated certificate into your browser to have it accepted.
  3. Shut envs and all env down (if running):
    ./cx envs down
    
  4. Execute the following command:
    ./cx envs up --certs-dir=<certificate_directory>
    
  5. Start one or more env:
    ./cx env up
    



[6]

Connect with MySQL Workbench

In order to connect to the database instance directly (for example to use reverse engineering with MySQL Workbench) follow these steps:

  • Shut your environment down
    cx env down
    
  • Edit the file docker-compose.yml in the root of your installation
  • In the section of the "db" container add the following lines
        ports:
          - 3306:3306
    
  • Save the file and start the environment
  • The database should now be reachable on localhost on the default port.

IMPORTANT:

  • Please note that only one env can be configured to do so at a time. Otherwise the database server will not start. You may choose different ports to expose different database servers at the same time.
  • The file docker-compose.yml will get overwritten on
    cx env config
    
    If you want to do this in a persistent way you may add it to _meta/docker-compose.tpl or fork the scripts repository.

Connect multiple ENVs to each other

Envs can talk to each other using their web container's full name. This allows direct communication from one instance to another. To get the full name of the web container call the following in the root directory of your ENV (assuming you use Envs):

echo "$(./cx envs list --dir=$PWD --real)_web_1"

Then you can do the following in another Env on the same machine:

./cx env shell
curl "http://<name_of_first_env>"

Development vs Production Environment

Use ./cx env config --mode=<mode> to switch between development and production environment. Available values for <mode> are:

  • development (default if not explicitly set)
  • production

Differences

Setup development production
phpMyAdmin Container Yes No
Mailhog Container Yes No
php-fpm pm dynamic static
php-fpm pm.max_children 5 100
php-fpm zend.assertions 1 -1

Enhancement ideas / Known problems

General

  • ENHANCEMENT: Add autocompletion
  • ENHANCEMENT: Add use-case for installing from package using the installer
  • PROBLEM: Cache autoconfig support for pre 5 is missing
  • PROBLEM: There's no way to access the MySQL server directly (which is a problem for the workflow when using MySQL workbench)
  • PROBLEM: If the directory used as web-root is owned by root, permissions do not work properly. This is because the user IDs cannot be mapped correctly.
  • PROBLEM: In case the name of the directory where the environment is being initialized does only contain numbers, then the script doesn't work as intented as it does wrongly interprete the hostname as IP address.
  • PROBLEM: cx does automatically read all data from standard input (in case there is any). This breaks the ability to call cx from within a while-loop reading from standard input as in while read input; do cx <command>; done;
    Workaround: call cx with input redirection. I.e.: cx <command> < /dev/null
    Proposed solution: do implement an argument (i.e.: -n) that prevents cx from reading from standard input

Commands

Env

  • ./cx env init should force domain URL and protocol
  • ./cx env down should be able to shut the environment down even if the configuration has changed since "up"
  • ./cx env update --db should work for non-dockerized databases
  • ./cx env up should show URLs
  • ENHANCEMENT: ./cx env init: GIT checkout output very long (branch list). This is very annoying on Windows, since output is very slow there
  • ENHANCEMENT: Add parameters to ./cx env shell to start shell of all containers
  • ENHANCEMENT: Autoscaling cannot be configured
  • ENHANCEMENT: ./cx env config should check if the configured images exist before writing docker-compose.yml
  • ENHANCEMENT: Admin contact should be set
  • ENHANCEMENT: ./cx env update should have an argument to specify another SQL dump
  • PROBLEM: Make the port for phpMyAdmin configurable
  • PROBLEM: Changing the hostname loses the db volume
  • PROBLEM: ./cx env update should update GIT first, then Docker, then reconfigure the environment (only if cx or docker-compose.tpl has changed, ask user if he wants to, db will get dropped), then update the database
  • PROBLEM: ./cx env update assumes that the environment is up but does not check it
  • PROBLEM: ./cx env update does not update _meta

Envs

  • Automatically adopt/release existing environments on up/down
  • Add subcommand "./cx envs locate <env>" to find working directory of an environment (or integrate this in "./cx envs list")
    • Allow filtering to get all environments that are pointing to the same working directory
  • ENHANCEMENT: HTTPS support is missing
  • ENHANCEMENT: If socket path is not standard linux config, proxy container will not work

Debug

  • ENHANCEMENT: Add parameter to debug all of the environment's containers

Other commands

Platform specific

Windows

  • Add a shortcut for the bash shell of the Ubuntu wrapper container
  • ./cx help fails if a command is specified (request is redirected to PHP)
  • Commands executed in the wrapper may fail due to missing proxy host directory
  • ENHANCEMENT: Add a default user to cloudrexx/ubuntu image (other than root)
  • ENHANCEMENT: Add development environment scripts to cloudrexx/ubuntu image
  • ENHANCEMENT: If socket path is not standard linux config, proxy container will not work
  • INFO: After "./cx env init", cx is deleted. The script automatically re-fetches it on next run. If you choose another branch than "master" (or a repository with a different state than the default one) you may have the wrong version of cx. Additionally, the command shows "error: unable to create file cx: No such file or directory" during execution.
    • The reason for this is Windows' behavior with files that are executed. They seem to be locked somehow.
  • PROBLEM: There might be a problem if the directory name is long

MacOS X

  • PROBLEM: The script does not work as MacOS includes Bash version 3 (version 4 is required).
  • PROBLEM: The local directory (/root/cx) displayed in message "sudo cp /root/cx /usr/local/bin" is wrong (its taken from the wrapper container instead from the host).

Version specific

1.x

All problems for versions 2, 3 and 4 will exist as well.

  • PROBLEM: Untested

2.x

All problems for versions 3 and 4 will exist as well. No known problems specific to this version.

3.x

All problems for version 4 will exist as well. No known problems specific to this version.

4.x

  • ./cx env config does not automatically configure the environment
  • Port config is missing
  • Offset path in .htaccess is wrong
  • PROBLEM: Caching autoconfig is missing
  • PROBLEM: .gitignore is not up to date in branch / .gitignore should be forced for all versions
  • PROBLEM: Config might get lost

5.x

  • PROBLEM: Port configuration might get overwritten.

References