원문 캡처 · github.com
원문 캡처 · github.com

anyctr는 Docker 방식의 명령을 Docker, Podman, Apple의 container에서 공통으로 사용할 수 있게 하는 CLI 게이트웨이다. macOS, Linux, Windows에서 런타임별 명령 차이를 줄이면서, 지원하지 않는 옵션은 조용히 무시하지 않고 오류로 알린다.

sh
$ anyctr run -d -p 8080:80 --name web nginx:alpine
$ anyctr ps
$ anyctr logs -f web
$ anyctr exec -it web sh

이 네 명령은 세 런타임에서 바꾸지 않고 사용할 수 있다. 내부적으로 exec 명령은 Docker와 Podman에서는 docker exec -it web sh, podman exec -it web sh로, Apple의 container에서는 container exec --interactive --tty web sh로 변환된다.

설치와 런타임 선택

설치는 Homebrew, 설치 스크립트, Go 또는 저장소 복제 방식으로 할 수 있다. Go 설치에는 Go 1.25 이상이 필요하다.

sh
brew install pedrospdc/tap/anyctr
sh
curl -fsSL https://raw.githubusercontent.com/pedrospdc/anyctr/main/install.sh | sh
sh
go install github.com/pedrospdc/anyctr/cmd/anyctr@latest # requires Go 1.25+
make install

사전 빌드 바이너리는 각 릴리스에 체크섬과 함께 제공된다. 대상은 darwin, linux, windows의 amd64와 arm64다. Windows에서는 .zip을 내려받아 anyctr.exe를 PATH에 두면 된다.

anyctr runtime list는 기기에 설치된 런타임과 버전, 바이너리 경로를 보여준다. --runtime 또는 ANYCTR_RUNTIME으로 선택 런타임을 지정할 수 있으며, 우선순위는 명령별 --runtime, 셸 환경 변수, 설정 파일 고정값, 설정된 자동 탐지 순서다. 고정한 런타임이 설치되지 않았다면 다른 런타임으로 조용히 전환하지 않고 오류를 낸다.

실행하지 않고 명령이 어떻게 바뀌는지 확인하려면 --explain을 사용한다. 설치되지 않은 런타임을 대상으로도 확인할 수 있어 스크립트를 커밋하기 전 이식성을 살펴볼 수 있다.

sh
$ anyctr --explain --runtime=container run -d -p 8080:80 --name web nginx:alpine
runtime: container (apple/container 1.2.2)
binary: /usr/local/bin/container
command: /usr/local/bin/container run --detach --name web --publish 8080:80 nginx:alpine

런타임별 차이와 예외 처리

Apple의 container는 컨테이너 목록 명령으로 ps 대신 list를 쓰고, 이미지 명령도 container image ls 형태다. --restart, --privileged, Compose는 제공하지 않는다. Podman은 Docker와 인자 구성이 호환되지만 기본적으로 루트 권한 없이 실행되며, GPU와 로깅 처리 방식이 다르다.

anyctr는 대상 런타임이 지원하지 않는 옵션을 기본적으로 오류 처리한다. 예를 들어 Apple의 container에서 다음을 실행하면 --restart가 지원되지 않는다고 알린다.

sh
$ anyctr run --restart=always -d nginx
anyctr: error: --restart is not supported by runtime "container" (apple/container 1.2.2)

필요하면 --relax로 해당 실행에서 지원되지 않는 옵션을 경고와 함께 버리거나, 특정 옵션을 항상 버리도록 설정할 수 있다. strict를 끄면 변환할 수 없는 옵션을 전반적으로 버린다. 런타임 전용 기능을 그대로 쓰려면 변환을 거치지 않는 raw 명령을 사용할 수 있다.

sh
anyctr --relax run --restart=always -d nginx
anyctr config set flags.restart drop
anyctr config set strict false
sh
anyctr raw run --rosetta --rm -it alpine sh

명령과 플래그별 지원 현황은 기능 문서에서 볼 수 있다. 차이가 있는 항목만 보려면 anyctr runtime capabilities, 전체 표는 anyctr runtime capabilities --all, 특정 명령은 anyctr runtime capabilities run을 사용한다. 알 수 없는 플래그는 추측해 처리하지 않고 거부하며, 오류에서 anyctr raw 사용을 안내한다.

Compose와 Docker 대체 명령

anyctr compose는 런타임이 제공하는 Compose 구현으로 인자를 그대로 전달하며, Compose 파일 자체는 파싱하지 않는다. Docker에서는 docker compose 플러그인 또는 독립 실행형 docker-compose를, Podman에서는 podman compose를 이용한다. Apple의 container에는 Compose가 포함되지 않아 별도 프로젝트인 container-compose를 사용한다.

필요한 Compose 제공자가 없으면 anyctr compose는 설치 안내를 표시하고 설치 여부를 묻는다. CI처럼 대화형 터미널이 없거나 사용자가 거절하면 프롬프트에서 기다리지 않고 안내와 함께 종료한다.

기존 스크립트나 Makefile이 docker를 호출한다면 anyctr alias로 docker라는 심볼릭 링크를 만들 수 있다. 셸 별칭이 아니라 심볼릭 링크를 쓰므로 /bin/sh를 실행하는 Makefile에서도 동작한다. 실제 docker 명령이 이미 있으면 --force를 주지 않는 한 덮어쓰지 않는다. 링크는 anyctr alias --remove로 제거할 수 있다.

sh
anyctr completion zsh > "${fpath[1]}/_anyctr" # bash, fish, powershell too

셸 자동 완성은 bash, fish, PowerShell도 지원한다. 설정 파일은 기본적으로 ~/.config/anyctr/config.toml을 사용하며 Windows에서는 %APPDATA%\\anyctr\\config.toml을 사용한다. $ANYCTR_CONFIG으로 경로를 덮어쓸 수 있다.

Apple의 container에서 시스템 서비스가 실행 중이 아니라는 오류가 나면 부팅할 때 한 번 container system start를 실행해야 한다. 포트 전달은 -p 옵션이 받아들여져 기록되더라도 런타임 네트워킹이 활성화돼야 작동한다. 포트 전달이 되지 않을 때도 각 컨테이너에는 라우팅 가능한 IP가 할당되며, anyctr ps에서 확인할 수 있다.

저장소의 개발 안내는 단위·변환 테스트, 런타임 CLI의 --help와 대조하는 적합성 검사, 실제 런타임을 이용한 통합 테스트를 구분한다. 프로젝트 설명에 따르면 Apple의 container는 GitHub 호스팅 macOS 러너에서 중첩 가상화를 사용할 수 없어 통합 테스트에 자체 호스팅 Apple 실리콘 러너나 개발자 Mac이 필요하다. 해당 런타임의 적합성 검사는 가상 머신을 시작하지 않으므로 호스팅 러너에서 작동할 가능성이 있으며, conformance-apple 작업은 workflow_dispatch 뒤에 설정돼 있다.

향후 계획에는 containerd/nerdctl 어댑터, 외부 제공자가 필요 없는 내장 Compose 엔진, inspect, cp, network, volume 명령이 포함된다. 라이선스는 MIT다. 설계와 런타임·명령 추가 방법은 아키텍처 문서, 라이선스 전문은 LICENSE에서 확인할 수 있다.