Ide got renamed to Dojo and was rewritten from Bash to Golang. If you need help with migrating your ide Docker images, please create a Github issue.
Provides an isolated, reproducible, well-defined environment for your project.
There are several ways of installing ide, choose one:
- Run:
sudo bash -c "`curl -L https://raw.githubusercontent.com/ai-traders/ide/master/install.sh`" - Follow instructions from install.sh.
- Run:
If you want to install from a specified tag, e.g.
git clone --depth 1 --single-branch https://github.com/ai-traders/ide.git ./ide/local_install.sh rm -r ./ide
0.8.0, add:-b 0.8.0option togit clonecommand.
- Bash
- Docker
Create a file: ./Idefile, e.g.:
IDE_DOCKER_IMAGE="xmik/ideide:3.0.2"
IDE_DOCKER_OPTIONS="--privileged"
Idefile points to an isolated, reproducible, well-defined environment.
Run:
$ ide bats --version
# some log messages omitted
08-11-2018 13:45:29 IDE entrypoint info: using ideide:3.0.2
Bats 0.4.0What happens:
- IDE determines that docker image
xmik/ideide:3.0.2is needed. - IDE creates a container from
xmik/ideide:3.0.2image, mounts current directory as/ide/workinside the container. - IDE runs
bats --versionin the container.
Run:
$ ide
# some log messages omitted
08-11-2018 13:48:00 IDE entrypoint info: using ideide:3.0.2
ide@fac6c0976cd1:/ide/work$ whoami
ide
ide@fac6c0976cd1:/ide/work$ exit
exit
$What happens:
- IDE determines that docker image
xmik/ideide:3.0.2is needed. - IDE creates a container from
xmik/ideide:3.0.2image, mounts current directory as/ide/workinside the container, sets flags:-ti. - IDE runs the default command for a docker image. It is
/bin/bashforxmik/ideide.
Current implementation limitations:
- works only on local docker host (docker daemon must be installed locally).
- works only on Linux (tested on Ubuntu/Debian and Alpine).
For debug output set IDE_LOG_LEVEL=debug.
$ ide --help
Usage: /usr/bin/ide [-c COMMAND] [options]
--command | -c Set IDE command, supported: run, pull, help, version.
Should be passed as first option. Default: run.
-c run Run docker or docker-compose run command.
-c pull Pull docker images specified in Idefile, do not run docker run, do not verify Idefile.
-c help | --help Help. Display this message and quit.
-c version | --version Version. Print version number and quit.
Options for run command:
--idefile /path/to/Idefile Specify IDEFILE, default is: ./Idefile
--dryrun Do not pull docker image, do not run docker run, verify Idefile.
Unset by default.
--force_not_interactive | --not_i Do not run docker containers interactively.
--no_rm Do not remove docker containers after run. Unset by default.
Implemented for docker driver only. Generates ./iderc and ./iderc.txt
files with container name.
CMD Command to be run in a docker container. Unset by default.
Options for pull command:
--idefile /path/to/Idefile Specify IDEFILE, default is: ./Idefile
--dryrun Do not pull docker image, do not run docker run, verify Idefile.
Unset by default.Configuration is kept in an Idefile. It is an environment variable style
file (e.g IDE_DRIVER=docker). It should be put in a root directory of your
project.
Supported variables:
IDE_DRIVER, supported values: docker, docker-compose, nvidia-docker. Default: dockerIDE_IDENTITY, a directory on localhost to be read-only mounted into container as/ide/identity, defaults toHOMEIDE_WORK, a directory on localhost to be read-write mounted into container asIDE_WORK_INNERdirectory. This is your working copy, your project repository. Defaults to current directory. Thanks to this, your project's code is visible inside the container (so its has code to work on) and you can see any container's work result (code changes).IDE_WORK_INNER, a directory in docker container to whichIDE_WORKlocal directory is mounted. Defaults to/ide/work.- variables only for docker driver:
IDE_DOCKER_IMAGE, the only required setting, docker image (or in the future maybe openstack image) to useIDE_DOCKER_OPTIONSwill append the string into docker run command. This is a fallback, because I can’t predict all the ide usage but I think such a fallback will be needed. Use it e.g. to set--privilegedor publish ports.- if
DISPLAYenvironment variable is set (to anything at all), then you can use ide with graphical applications.
- variables only for docker-compose driver:
IDE_DOCKER_COMPOSE_FILE, the file used by docker-compose. Default:docker-compose.yml.IDE_DOCKER_COMPOSE_OPTIONSwill append the string into docker-compose run command. This is a fallback, because I can’t predict all the ide usage but I think such a fallback will be needed. Use it e.g. to set--service-ports.
Idefile:
IDE_DOCKER_IMAGE="xmik/ideide:3.0.2"
IDE_DOCKER_OPTIONS="--privileged"
Idefile:
IDE_DRIVER="nvidia-docker"
IDE_DOCKER_IMAGE="some_nvidia_image:latest"
This driver differs from docker driver in 1 way only: instead of docker run
command, it uses nvidia-docker run. You have to have installed: nvidia-docker
Example Idefile for docker-compose driver:
IDE_DRIVER="docker-compose"Example docker-compose.yml version 1:
alpine:
image: "alpine:3.5"
entrypoint: ["/bin/sh", "-c"]
# Uncomment this if you want to test with long running command
# I chose short running command because it is faster to stop this container.
# command: ["while true; do sleep 1d; done;"]
command: ["true"]
default:
image: "xmik/ideide:3.0.2"
links:
- alpine
volumes:
- ${IDE_IDENTITY}:/ide/identity:ro
- ${IDE_WORK}:/ide/work
env_file:
- ${ENV_FILE}It has to contain: "IDE_IDENTITY", "IDE_WORK", "ENV_FILE", mount the
IDE_IDENTITY with :ro and contain a "default" docker container.
If you want other containers, in docker-compose.yml file, to be ran too, you
have to link them like above.
Example docker-compose.yml version 2:
version: '2'
services:
alpine:
image: "alpine:3.5"
entrypoint: ["/bin/sh", "-c"]
# Uncomment this if you want to test with long running command
# I chose short running command because it is faster to stop this container.
# command: ["while true; do sleep 1d; done;"]
command: ["true"]
default:
image: "xmik/ideide:3.0.2"
depends_on:
- alpine
volumes:
- ${IDE_IDENTITY}:/ide/identity:ro
- ${IDE_WORK}:/ide/work
env_file:
- ${ENV_FILE}The same requirements apply as for docker-compose.yml version 1, but here you can
also use depends_on docker-compose configuration.
We believe any project should be built/tested by running:
git clone <project-url>
ide <development-command>regadless of software installed on the host where this was called.
ide is useful when:
- Your project often changes and needs different development environment all the time (e.g. newer java, more development tools, environment configuration changes). Installing those on a workstation could pollute it. Installing anything without a script not reproducible at all. Reprovisioning the whole workstation is neither safe nor comfortable.
- Your code compiled a month ago on your workstation, but it does not now. That build is not reproducible.
- You have a new computer/hardware/OS. Without
ide, you'd have to provision all the tools from the beginning at once (even if you already don't need a half of them). - Your project is complex and needs a lot of tools to be developed (e.g. Ruby
and Chef and Cpp and Mono). It can be hard to install them all on one workstation.
With
ide, you can have many Idefiles, each one pointing to different development environment. - You work on many projects and it is impossible to have all the versions of development tools installed on your workstation.
- Your code works on your machine. But it does not work on some Continuous Integration. Your workstation and CI agent should use the same environment. Your project should specify which environment it needs. Same if there are many developers - each one should use the same environment. Forgetting configuration or secret files was one of the most frequent causes of failed CI jobs for us.
- You want to show case your code to others, but don't want to force them
to install and setup all the dependencies/development tools. Now, they can
just run:
ide. - You want to experiment, but don't want to pollute your workstation and
you want to work on local code base. Use
ideinteractively.
ide wraps docker. It will
- fetch development/dependencies tools
- ensure environment configuration
- mount volumes from host to container(s), so that source code is on your workstation, but the environment is in docker image
Using ide there is no need to update CI agents/workstations whenever your
project environment changes. You only need Docker/Docker-compose, Bash and
ide installed and some secrets available. Thanks to that, we close all configuration problems of a particular
project type in a single ide docker image.
If you want to create a Docker image that can be used by ide, the best is to see ideide and treat it as example.
First, choose a name. A convention for all ide docker images names is to end with 'ide', e.g.:
- rubyide
- cppide
- someverylongname-ide
Then, write a readme to help you decide:
- which configuration or secret files must exist on host (in IDE_IDENTITY directory)
- what is available by default, e.g. must I run
chef exec rakeor can justrake, what is current directory in docker container - example Idefile
- example command
- what is the development process
Then, read ide_image_scripts/Readme.md and use ide_image_scripts/install.sh script in your Dockerfile. The script helps with:
When we mount a volume from localhost into a docker container:
$ docker run -ti -v $(pwd)/test/integration:/tmp/ide-test alpine:3.5 /bin/sh
/ # ls -la /tmp/ide-test/
total 12
drwxrwxr-x 3 1000 1000 4096 Mar 7 11:24 .
drwxrwxrwt 1 root root 4096 Apr 17 16:55 ..
drwxrwxr-x 2 1000 1000 4096 Apr 16 16:10 shpec
The files owner has the same UID and GID as the files owner on localhost (docker host).
Ide Docker image must have some not-root user. Use ide user for convention. Its uid and gid should be: 1000, because there is a convention that main (human) linux user has uid and gid 1000.
We need to:
- ensure
/ide/workand ide user home are owned by ide user with the uid and gid of/ide/workdirectory - if docker image already contains files owned by
ideuser, (e.g./ide/home), then after changing uid and gid we have to search for all those files and update their ownership. - avoid mounting anything into
/ide/workas root.
Thanks to Tom's docker-uid-gid-fix
project, we are armed with PoC how to achieve this. We change the uid and gid of
ide user with the destined uid and gid. This is done by /etc/ide.d/scripts/50-ide-fix-uid-gid.sh script.
The entrypoint should:
- source any scripts from
/etc/ide.d/variables/*. - invoke any scripts from
/etc/ide.d/scripts/*. - enable end user to run the docker image interactively or not.
- change the current directory into
/ide/work(this may be done in/home/ide/.profile). - it could say which docker image name and tag it runs in.
- Entrypoint should map any settings and secrets files from IDE_IDENTITY into
/home/ide/. Do it by copying and changing ownership and setting permissions toideuser. Do it e.g. in/etc/ide.d/scripts/20-ide-setup-identity.shscript. - If you want, you can map any files from
${IDE_IDENTITY}/.bashrc.d/and from${IDE_IDENTITY}/profile.d/, because your entrypoint can ensure to run in login shell. If your host's shell is interactive, docker will be ran interactively too. - Exit with non 0 status if any obligatory config or secret file does not exist (tell which files are missing).
- In order to limit the requirements put on docker host, it seems better to generate configuration files instead of requiring them to exist on docker host (unless impossible or uncomfortable or configuration files contain secrets).
- It is usually better to first copy the whole configuration directory like
.sshor.chef, so that any secrets are copied and then (either or not) generate some configs. - Watch out for symlinks: https://aitraders.tpondemand.com/entity/8464 . E.g.
if you have dotfiles repository and you have such symlinks in your HOME like:
/home/user/.gitconfig -> /home/user/code/dotfiles/.gitconfig, inside docker container this symlink is:/ide/identity/.gitconfig -> /home/user/code/dotfiles/.gitconfigand/home/user/code/dotfiles/.gitconfigdoes not exist. The only known workaround: do not have symlinks, use plain files.
You can choose sudo command to change user from root to ide. Example sudo command:
sudo -E -H -u ide /bin/bash -lc "$@"Working example is in entrypoint.sh
If you want to run your ide docker image without using its default entrypoint, run e.g.:
docker run --rm -ti --entrypoint=/bin/bash example-ide:0.0.1 -c "/bin/bash"
Thanks to ENTRYPOINT taking care of all configuration, secrets, ownership, current
directory, the CMD can be as simple as possible, as if you ran it on fully
provisioned instance. Example: rake style:rubocop or some mono command.
If your ide docker image should have docker daemon:
- use overlay docker storage driver (#8149)
- set
/var/lib/dockeras docker volume (#8268) - run such ide docker container with
--privileged, setIDE_DOCKER_OPTIONS="--privileged"
Without the above, you'll see e.g.:
dpkg: error: error removing old backup file '/var/lib/dpkg/status-old': Operation not permitted
E: Sub-process /usr/bin/dpkg returned an error code (2)
Frequently evolving IDE images are very ok. You should not just start using new tools without building and testing new dev image first.
I recommend to use local tasks file, just like the one ideide uses. Example tasks:
./tasks build # run docker build
./tasks itest # run integration tests
./tasks publish # run docker push
The most important is to test the end user use cases, that e.g. ide rake build
will really compile your code and produce an artifact.
- The scripts to be put into
/etc/ide.d/scriptsdirectory should not only copy files, but also ensure proper permissions. E.g.~/.ssh/id_rsashould have permissions:600. - Why not mount
/home/useras/home/idebut as/ide/work? Because/home/idein ide docker image can already have some configuration and mounting it this way would override all the provisioned files.
- Make changes in a feature branch, created from a git tagged commit in master branch.
- You run tests:
And the following tasks you can run using either default Idefile, on Ubuntu:
$ ./tasks style $ ./tasks unit $ ./tasks unit_alpine
or on Alpine:$ ide ./tasks itest_build_exampleide ./tasks itest ./tasks itest_install ./tasks itest_local_install cd ide_image_scripts && ./tasks itest_build_images && ./tasks itest_configs && ./tasks itest
The$ ide --idefile Idefile.alpine # same as for default Idefiletasksfile contains guidelines how to install testing software if you can't run in ide docker image. - If you decide that your code is ready, create a PR. Your job as a contributor is done.
Then:
- Maintainer merges PR(s) into master branch.
- Maintainer runs locally:
./tasks set_versionto set version in CHANGELOG and ide_version files to the version from OVersion backend- e.g.
./tasks set_version 1.2.3to set version in CHANGELOG and ide_version files and in OVersion backend to 1.2.3
- Everything is pushed to master onto private git server.
- CI server (GoCD) tests and releases IDE.
- After successful CI server pipeline, an maintainer pushes master to github.
This project is licensed under the GNU Lesser General Public License v3.0 license.