Git Product home page Git Product logo

podman-bootc's Introduction

Streamlining podman + bootc interactions

This project aims to address containers/podman#21243 in alignment with the https://github.com/containers/bootc project.

Goals

Setup

Requirements:

  • bootc extension requirements
    • (Even on Linux, you must set up podman machine with a rootful connection; see below)
    • podman machine init --rootful --now
  • qemu-system-x86_64 / qemu-system-aarch64
  • xorriso/osirrox
  • golang
  • libvirt-devel

To compile it, just run in the project directory:

make

MacOS

On MacOS you can use homebrew to install podman-bootc

brew tap germag/podman-bootc
brew install podman-bootc

alternatively, you can download the latest development cutting-edge source

brew install --head podman-bootc

It will install xorriso and libvirt, but it doesn't install qemu. You need to install qemu manually, using brew:

brew install qemu

or by other mean and make it available in the path.

Fedora

For Fedora 40 and Rawhide we provide a COPR repository. First, enable the COPR repository:

sudo dnf -y install 'dnf-command(copr)'
sudo dnf -y copr enable gmaglione/podman-bootc

then you can install podman-bootc as usual:

sudo dnf -y install podman-bootc

Running

The core command right now is:

podman-bootc run <imagename>

This command creates a new virtual machine, backed by a persistent disk image from a "self install" of the container image, and makes a SSH connection to it.

This requires SSH to be enabled by default in your base image; by default an automatically generated SSH key is injected via a systemd credential attached to qemu.

Even after you close the SSH connection, the machine continues to run.

Other commands:

  • podman-bootc list: List running VMs
  • podman-bootc ssh: Connect to a VM
  • podman-bootc rm: Remove a VM

Architecture

At the current time the run command uses a bootc install flow - where the container installs itself executed in a privileged mode inside the podman-machine VM.

The installation target is a raw disk image is created on the host, but loopback mounted over virtiofs/9p from the podman-machine VM.

(The need for a real-root privileged container to write Linux filesystems is part of the rationale for requiring podman-machine even on Linux is that it keeps the architecture aligned with MacOS (where it's always required))

In the future, support for installing via Anaconda and bootc-image-builder will be added.

podman-bootc's People

Contributors

germag avatar ckyrouac avatar cgwalters avatar jeckersb avatar lmilbaum avatar cfergeau avatar rhatdan avatar omertuc avatar platform-engineering-bot avatar

Stargazers

s3rj1k avatar Caleb Woodbine avatar adam kaminski avatar Robert Sturla avatar  avatar Mick Pollard avatar  avatar Xiaofeng Wang avatar Elliot Speck avatar Alberto Faria avatar Jorge O. Castro avatar Ethan Li avatar Aymeric avatar Eric Curtin avatar

Watchers

Mrunal Patel avatar  avatar Jason T. Greene avatar  avatar Chris Evich avatar  avatar  avatar Preethi Thomas avatar Mohan Boddu avatar  avatar Brent Baude avatar

podman-bootc's Issues

Unable to run amd64 image

I built an amd64 image using podman build --platform linux/amd64 -t fedora-helloworld-test .

I then tried running it with podman-bootc:

▶ podman-bootc run fedora-helloworld-test
WARNING: image platform (linux/amd64) does not match the expected platform (linux/arm64)
ERROR Re-exec in host mountns: setns: EINVAL: Invalid argument
ERROR Installing to disk: Gathering source info from container env: Task podman inspect failed: ExitStatus(unix_wait_status(256))
Error: unable to install bootc image: failed to create disk image: failed to run bootc install

Linux: cannot run a poweroff machine

https://gitlab.com/bootc-org/podman-bootc-cli/-/issues/30

The libvirt domain definition is not removed after poweroff:

$ podman-bootc run --background quay.io/centos-bootc/fedora-bootc:eln

$ podman-bootc list
ID            REPO                                   SIZE        CREATED         RUNNING     SSH PORT
d35a6b59649a  quay.io/centos-bootc/fedora-bootc:eln  10.7GB      43 minutes ago  false       40277

$ podman-bootc ssh d35a6b59649a
[root@localhost ~]# poweroff 
[root@localhost ~]# Connection to localhost closed by remote host.

$ podman-bootc run --background quay.io/centos-bootc/fedora-bootc:eln
Booting the VM...
Error: runBootcVM: unable to define virtual machine domain: virError(Code=9, Domain=20, Message='operation failed: domain 'podman-bootc-d35a6b59649a' already exists with uuid dd3eb53d-6900-47c8-8cd9-b61a2d890ca5')

$ virsh list --all
 Id   Name                         State
-------------------------------------------
 -    podman-bootc-d35a6b59649a   shut off

Support multiple VMs of the same container image

Currently, there is a 1:1 map between the VM in the cache and the OCI image.

I believe there are valid use cases for wanting to run more than one VM of the same OCI images. The point is, do these use cases fall within the scope of podman-bootc?, What would it look like from the UI POV?, for instance, the user needs to request a new VM:

podman bootc run --new-vm <imagename>

or every run creates a new VM if there is an existent VM already

How that will work when we need to rebuild the disk image, if for instance the disk size changes:

1) podman-bootc run --disk-size 20G image0
...
2) podman-bootc run --disk-size 25G image0

2) should create a new VM?, or only if 1) is still running. Or we replace the previous one unless --new-vm?, or by default is a new vm unless --replace-vm?

If we have more than one VM of the same OCI image, which of those we start on run, should we need to add --vm <vm_id>?

If we don't want to do this "automagically", we will need to manage the VMs as persistent objects with its own IDs.
I want to have this discussion before starting the work on the cache code, because it changes pretty much everything.

integration tests

I would like to add some integration tests. Running them on all supported platforms (Win, Mac, Linux) will be a herculean task but we could start with Linux.

I am fluent in bats but maybe there are other options/preferences.

@germag @cgwalters WDYT?

support running via virtiofs

https://gitlab.com/bootc-org/podman-bootc-cli/-/issues/31

It'd be nice to have podman-bootc run --virtiofs <container> that would set things up to boot via virtiofs root. I think to really make this work sanely, we'd need to move the container storage out of the podman-machine VM and on to the host. That would have all sorts of implications.

Failing that, maybe we could do run --nfs to set up a NFS-backed rootfs talking to a NFS server serving the container storage on the target.
I think composefs will help here in both cases, as we can have all the selinux labels and metadata set up in the composefs, and have the virtiofs/nfs be a lower FS just fetching the backing files.

Either way steps would also include

  • Extracting kernel/initramfs from the container
  • Setting up qemu to launch things that way

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Awaiting Schedule

These updates are awaiting their schedule. Click on a checkbox to get an update now.

  • chore(deps): update go updates (github.com/BurntSushi/toml, github.com/Microsoft/go-winio, github.com/Microsoft/hcsshim, github.com/adrg/xdg, github.com/bytedance/sonic, github.com/cilium/ebpf, github.com/containerd/containerd, github.com/containerd/typeurl/v2, github.com/containers/buildah, github.com/containers/common, github.com/containers/gvisor-tap-vsock, github.com/containers/image/v5, github.com/containers/libhvee, github.com/containers/ocicrypt, github.com/containers/podman/v5, github.com/containers/storage, github.com/crc-org/crc/v2, github.com/cyphar/filepath-securejoin, github.com/digitalocean/go-libvirt, github.com/distribution/reference, github.com/docker/docker, github.com/docker/docker-credential-helpers, github.com/fsouza/go-dockerclient, github.com/gabriel-vasile/mimetype, github.com/gin-gonic/gin, github.com/go-jose/go-jose/v3, github.com/go-logr/logr, github.com/go-openapi/analysis, github.com/go-openapi/errors, github.com/go-openapi/jsonpointer, github.com/go-openapi/jsonreference, github.com/go-openapi/loads, github.com/go-openapi/runtime, github.com/go-openapi/spec, github.com/go-openapi/strfmt, github.com/go-openapi/swag, github.com/go-openapi/validate, github.com/go-playground/validator/v10, github.com/goccy/go-json, github.com/gofrs/flock, github.com/golang/protobuf, github.com/google/go-containerregistry, github.com/google/pprof, github.com/gorilla/schema, github.com/klauspost/compress, github.com/klauspost/cpuid/v2, github.com/leodido/go-urn, github.com/letsencrypt/boulder, github.com/lufia/plan9stats, github.com/mattn/go-runewidth, github.com/moby/buildkit, github.com/moby/sys/mountinfo, github.com/moby/sys/sequential, github.com/moby/sys/user, github.com/oklog/ulid, github.com/onsi/ginkgo/v2, github.com/onsi/gomega, github.com/opencontainers/runc, github.com/openshift/imagebuilder, github.com/pelletier/go-toml/v2, github.com/power-devops/perfstat, github.com/shirou/gopsutil/v3, github.com/sigstore/fulcio, github.com/sigstore/rekor, github.com/sigstore/sigstore, github.com/spf13/cobra, github.com/stefanberger/go-pkcs11uri, github.com/sylabs/sif/v2, github.com/tklauser/go-sysconf, github.com/tklauser/numcpus, github.com/ulikunitz/xz, github.com/vbauerster/mpb/v8, go.mongodb.org/mongo-driver, go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp, go.opentelemetry.io/otel, go.opentelemetry.io/otel/metric, go.opentelemetry.io/otel/trace, golang.org/x/arch, golang.org/x/crypto, golang.org/x/exp, golang.org/x/mod, golang.org/x/net, golang.org/x/sync, golang.org/x/sys, golang.org/x/term, golang.org/x/text, golang.org/x/time, golang.org/x/tools, google.golang.org/genproto/googleapis/rpc, google.golang.org/grpc, google.golang.org/protobuf, gopkg.in/go-jose/go-jose.v2, libvirt.org/go/libvirt, tags.cncf.io/container-device-interface)

Warning

Renovate failed to look up the following dependencies: Could not determine new digest for update (go package github.com/go-task/slim-sprig).

Files affected: go.mod


Detected dependencies

github-actions
.github/workflows/ci.yml
  • actions/checkout v4
gomod
go.mod
  • go 1.20
  • github.com/adrg/xdg v0.4.0
  • github.com/containers/common v0.58.1
  • github.com/containers/podman/v5 v5.0.1
  • github.com/docker/go-units v0.5.0
  • github.com/gofrs/flock v0.8.1
  • github.com/onsi/ginkgo/v2 v2.17.1
  • github.com/onsi/gomega v1.32.0
  • github.com/opencontainers/runtime-spec v1.2.0
  • github.com/sirupsen/logrus v1.9.3
  • github.com/spf13/cobra v1.8.0
  • golang.org/x/crypto v0.22.0
  • golang.org/x/sys v0.19.0
  • libvirt.org/go/libvirt v1.10002.0
  • dario.cat/mergo v1.0.0
  • github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161@306776ec8161
  • github.com/BurntSushi/toml v1.3.2
  • github.com/Microsoft/go-winio v0.6.1
  • github.com/Microsoft/hcsshim v0.12.0-rc.3
  • github.com/VividCortex/ewma v1.2.0
  • github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d@5a71ef0e047d
  • github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2@a9d515a09cc2
  • github.com/blang/semver/v4 v4.0.0
  • github.com/bytedance/sonic v1.10.2
  • github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d@296ad89f973d
  • github.com/chenzhuoyu/iasm v0.9.1
  • github.com/chzyer/readline v1.5.1
  • github.com/cilium/ebpf v0.11.0
  • github.com/containerd/cgroups/v3 v3.0.3
  • github.com/containerd/containerd v1.7.13
  • github.com/containerd/errdefs v0.1.0
  • github.com/containerd/log v0.1.0
  • github.com/containerd/stargz-snapshotter/estargz v0.15.1
  • github.com/containerd/typeurl/v2 v2.1.1
  • github.com/containers/buildah v1.35.3
  • github.com/containers/gvisor-tap-vsock v0.7.3
  • github.com/containers/image/v5 v5.30.0
  • github.com/containers/libhvee v0.7.0
  • github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01@c1716e8a8d01
  • github.com/containers/ocicrypt v1.1.9
  • github.com/containers/psgo v1.9.0
  • github.com/containers/storage v1.53.0
  • github.com/containers/winquit v1.1.0
  • github.com/coreos/go-systemd/v22 v22.5.1-0.20231103132048-7d375ecc2b09@7d375ecc2b09
  • github.com/crc-org/crc/v2 v2.32.0
  • github.com/crc-org/vfkit v0.5.1
  • github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f@ba74d44ecf5f
  • github.com/cyphar/filepath-securejoin v0.2.4
  • github.com/digitalocean/go-libvirt v0.0.0-20220804181439-8648fbde413e@8648fbde413e
  • github.com/digitalocean/go-qemu v0.0.0-20230711162256-2e3d0186973e@2e3d0186973e
  • github.com/disiqueira/gotree/v3 v3.0.2
  • github.com/distribution/reference v0.5.0
  • github.com/docker/distribution v2.8.3+incompatible
  • github.com/docker/docker v25.0.3+incompatible
  • github.com/docker/docker-credential-helpers v0.8.1
  • github.com/docker/go-connections v0.5.0
  • github.com/felixge/httpsnoop v1.0.4
  • github.com/fsnotify/fsnotify v1.7.0
  • github.com/fsouza/go-dockerclient v1.10.1
  • github.com/gabriel-vasile/mimetype v1.4.3
  • github.com/gin-contrib/sse v0.1.0
  • github.com/gin-gonic/gin v1.9.1
  • github.com/go-jose/go-jose/v3 v3.0.3
  • github.com/go-logr/logr v1.4.1
  • github.com/go-logr/stdr v1.2.2
  • github.com/go-ole/go-ole v1.3.0
  • github.com/go-openapi/analysis v0.21.4
  • github.com/go-openapi/errors v0.21.1
  • github.com/go-openapi/jsonpointer v0.19.6
  • github.com/go-openapi/jsonreference v0.20.2
  • github.com/go-openapi/loads v0.21.2
  • github.com/go-openapi/runtime v0.26.0
  • github.com/go-openapi/spec v0.20.9
  • github.com/go-openapi/strfmt v0.22.2
  • github.com/go-openapi/swag v0.22.10
  • github.com/go-openapi/validate v0.22.1
  • github.com/go-playground/locales v0.14.1
  • github.com/go-playground/universal-translator v0.18.1
  • github.com/go-playground/validator/v10 v10.17.0
  • github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572@52ccab3ef572
  • github.com/goccy/go-json v0.10.2
  • github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466@76236955d466
  • github.com/gogo/protobuf v1.3.2
  • github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da@41bb18bfe9da
  • github.com/golang/protobuf v1.5.3
  • github.com/google/go-cmp v0.6.0
  • github.com/google/go-containerregistry v0.19.0
  • github.com/google/go-intervals v0.0.2
  • github.com/google/pprof v0.0.0-20230323073829-e72429f035bd@e72429f035bd
  • github.com/google/uuid v1.6.0
  • github.com/gorilla/mux v1.8.1
  • github.com/gorilla/schema v1.2.1
  • github.com/hashicorp/errwrap v1.1.0
  • github.com/hashicorp/go-multierror v1.1.1
  • github.com/inconshreveable/mousetrap v1.1.0
  • github.com/jinzhu/copier v0.4.0
  • github.com/josharian/intern v1.0.0
  • github.com/json-iterator/go v1.1.12
  • github.com/klauspost/compress v1.17.7
  • github.com/klauspost/cpuid/v2 v2.2.6
  • github.com/klauspost/pgzip v1.2.6
  • github.com/kr/fs v0.1.0
  • github.com/leodido/go-urn v1.2.4
  • github.com/letsencrypt/boulder v0.0.0-20230907030200-6d76a0f91e1e@6d76a0f91e1e
  • github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0@39d0f177ccd0
  • github.com/mailru/easyjson v0.7.7
  • github.com/manifoldco/promptui v0.9.0
  • github.com/mattn/go-colorable v0.1.13
  • github.com/mattn/go-isatty v0.0.20
  • github.com/mattn/go-runewidth v0.0.15
  • github.com/mattn/go-shellwords v1.0.12
  • github.com/mattn/go-sqlite3 v1.14.22
  • github.com/miekg/pkcs11 v1.1.1
  • github.com/mistifyio/go-zfs/v3 v3.0.1
  • github.com/mitchellh/mapstructure v1.5.0
  • github.com/moby/buildkit v0.12.5
  • github.com/moby/patternmatcher v0.6.0
  • github.com/moby/sys/mountinfo v0.7.1
  • github.com/moby/sys/sequential v0.5.0
  • github.com/moby/sys/user v0.1.0
  • github.com/moby/term v0.5.0
  • github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd@bacd9c7ef1dd
  • github.com/modern-go/reflect2 v1.0.2
  • github.com/morikuni/aec v1.0.0
  • github.com/nxadm/tail v1.4.11
  • github.com/oklog/ulid v1.3.1
  • github.com/opencontainers/go-digest v1.0.0
  • github.com/opencontainers/image-spec v1.1.0
  • github.com/opencontainers/runc v1.1.12
  • github.com/opencontainers/runtime-tools v0.9.1-0.20230914150019-408c51e934dc@408c51e934dc
  • github.com/opencontainers/selinux v1.11.0
  • github.com/openshift/imagebuilder v1.2.6
  • github.com/ostreedev/ostree-go v0.0.0-20210805093236-719684c64e4f@719684c64e4f
  • github.com/pelletier/go-toml/v2 v2.1.1
  • github.com/pkg/errors v0.9.1
  • github.com/pkg/sftp v1.13.6
  • github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c@5aafc221ea8c
  • github.com/proglottis/gpgme v0.1.3
  • github.com/rivo/uniseg v0.4.7
  • github.com/secure-systems-lab/go-securesystemslib v0.8.0
  • github.com/shirou/gopsutil/v3 v3.24.2
  • github.com/shoenig/go-m1cpu v0.1.6
  • github.com/sigstore/fulcio v1.4.3
  • github.com/sigstore/rekor v1.2.2
  • github.com/sigstore/sigstore v1.8.2
  • github.com/spf13/pflag v1.0.5
  • github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980@78d3cae3a980
  • github.com/sylabs/sif/v2 v2.15.1
  • github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635@42c35b437635
  • github.com/tchap/go-patricia/v2 v2.3.1
  • github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399@afe73141d399
  • github.com/tklauser/go-sysconf v0.3.12
  • github.com/tklauser/numcpus v0.6.1
  • github.com/twitchyliquid64/golang-asm v0.15.1
  • github.com/ugorji/go/codec v1.2.12
  • github.com/ulikunitz/xz v0.5.11
  • github.com/vbatts/tar-split v0.11.5
  • github.com/vbauerster/mpb/v8 v8.7.2
  • github.com/yusufpapurcu/wmi v1.2.4
  • go.mongodb.org/mongo-driver v1.14.0
  • go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352@33d05740a352
  • go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0
  • go.opentelemetry.io/otel v1.22.0
  • go.opentelemetry.io/otel/metric v1.22.0
  • go.opentelemetry.io/otel/trace v1.22.0
  • golang.org/x/arch v0.7.0
  • golang.org/x/exp v0.0.0-20240222234643-814bf88cf225@814bf88cf225
  • golang.org/x/mod v0.15.0
  • golang.org/x/net v0.22.0
  • golang.org/x/sync v0.6.0
  • golang.org/x/term v0.19.0
  • golang.org/x/text v0.14.0
  • golang.org/x/time v0.3.0
  • golang.org/x/tools v0.18.0
  • google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0@995d672761c0
  • google.golang.org/grpc v1.61.0
  • google.golang.org/protobuf v1.33.0
  • gopkg.in/go-jose/go-jose.v2 v2.6.3
  • gopkg.in/natefinch/lumberjack.v2 v2.2.1
  • gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7@dd632973f1e7
  • gopkg.in/yaml.v3 v3.0.1
  • sigs.k8s.io/yaml v1.4.0
  • tags.cncf.io/container-device-interface v0.6.2

Knowing if we are running arm or amd64, and ability to select them.

When I run for example podman-bootc run quay.io/centos-bootc/centos-bootc:stream9 which is a hosted manifest with multiple arch images, I was unsure if podman-bootc was going to run either arch.

I wasn't sure so I checked out podman-bootc --help and I could not find any options to pass in specifying arm64 or amd64.

`podman-bootc start` command for VM

$ podman-bootc list
ID            REPO                    SIZE        CREATED         RUNNING     SSH PORT
14ec31aa5da4  localhost/bootc:latest  10.7GB      39 minutes ago  false       33815

VM is RUNNING false, is there any way to start it? podman-bootc doesn't have any start command, is it expected from the user to simply podman-bootc run with the same image (I guess #42 seems related here)?

GUI pop-up and qemu screen?

So this works which is awesome!

But for some reason I am getting a qemu monitor screen appearing too when running it?

Screenshot 2024-05-06 at 9 25 19 AM

I had actually thought that it didn't work for a second because it showed the qemu monitoring screen, so I had closed it.

Running it again and waiting a bit longer, I saw that it connected via SSH fine in the end.

I feel like this is not intentional having the GUI pop up?

When running the pure qemu commands, I do not get a monitor screen, ex:

qemu-system-aarch64 \
    -m 8G \
    -M virt \
    -accel hvf \
    -cpu host \
    -smp 4 \
    -serial mon:stdio \
    -nographic \
    -netdev user,id=usernet,hostfwd=tcp::8080-:80 \
    -device virtio-net,netdev=usernet \
    -drive file=/opt/homebrew/share/qemu/edk2-aarch64-code.fd,format=raw,if=pflash,readonly=on \
    -drive file=$DISK_IMAGE,if=virtio,cache=writethrough,format=raw

Unused `WaitGroup`

Commit e7342b8 added a WaitGroup called vmConsoleWg, but I don't see Wait() being called anywhere on it, is this a bug, stale code, or maybe I'm misreading it?

@ckyrouac

support bootc-image-builder

https://gitlab.com/bootc-org/podman-bootc-cli/-/issues/26

Let's support a wrapper for https://github.com/osbuild/bootc-image-builder

This would first leverage CentOS/centos-bootc#453 to find the relevant image.

Also with this we should support being passed a config.

I'm envisioning:

podman-bootc run --via-bib

to start to do the disk image install that way to make it ergonomic to test. And that would happen automatically if passed podman-bootc run --image-config /path/to/config.json.

It'd also make sense to have
podman-bootc build-disk just be a direct wrapper for the podman run invocations for bib, allowing generic passthrough of everything there (e.g. could generate an ISO, qcow2 etc. without specifically running it)

Support MacOS on amd64

I'm getting the error "QEMU binary not found" despite having installed qemu using Homebrew. I see that the instruction set is hard coded as aarch64 for darwin.

Are you open for pull requests to support arm64 on darwin, or is that considered a dead platform? Personally, I'm fine either way. Will use a rejection as evidence to request a new MacBook. :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.