Why does FOO=bar; export the variable into my environment

No, FOO=bar; does not export the variable into my environment

A var is set in the (present) environment only if it was previously exported:

$ export foo
$ foo=bar
$ env | grep foo
foo=bar

A variable is set in the environment of a command when it is placed before the command. Like foo=bar command. And it only exists while the command runs.

$ foo=bar bash -c 'echo "foo is = $foo"'
foo is = bar

The var is not set for the command line (in the present shell):

$ foo=bar bash -c echo\ $foo

Above, the value of $foo is replaced with nothing by the present running shell, thus: no output.

Your command:

$ FOO=bar docker run -it -e FOO=$FOO debian env

is converted to the actual string:

$ FOO=bar docker run -it -e FOO= debian env

by the present running shell.

If, instead, you set the variable (in the present running shell) with foo=bar before running the command, the line will be converted to:

$ FOO=bar; docker run -it -e FOO=bar debian env

A variable set to the environment of a command is erased when the command returns:

$ foo=bar bash -c 'echo'; echo "foo was erased: \"$foo\""

Except when the command is a builtin in some conditions/shells:

$ ksh -c 'foo=bar typeset baz=quuz; echo $foo'
bar

There are a number of variations to consider:

  1. Just doing FOO=bar creates a variable named FOO with value bar, but that variable isn't passed along to new processes:

    $ echo $FOO
    $ FOO=bar
    $ echo $FOO
    bar
    $ bash        # Start a new bash process
    $ echo $FOO
                  # Variable is not set in the new process
    $ exit        # Exit new bash process
    
  2. Running FOO=bar <command> will run the given command with the variable set (but doesn't affect the original shell's environment):

    $ echo $foo
    $ FOO=baz bash   # start a new bash process
    $ echo $FOO
    baz
    $ exit           # exit the new bash process
    exit
    $ echo $FOO      
                     # No FOO in the original bash process
    $
    
  3. Doing FOO=foo; <command> is equivalent to (1); putting a semicolon between two commands is equivalent to running those two commands on two separate lines:

    $ FOO=foo; echo $FOO
    foo
    $ bash
    $ echo $FOO
    
    $ exit
    exit
    $ echo $FOO
    foo
    $
    
  4. Using export will pass a variable in the shell's environment to newly-created processes:

    $ export FOO=bar
    $ echo $FOO    # Value set in original shell
    bar
    $ bash         # Start another shell
    $ echo $FOO
    bar            # Value was passed along to new process
    $ exit
    exit
    

FOO=bar docker run -it -e FOO=$FOO debian env

Here the $FOO from FOO=$FOO will be expanded before the FOO=bar assignment happens.

You can check that with a more straight-forward example:

FOO=first
FOO=second echo FOO=$FOO
=> FOO=first

FOO=third; echo FOO=$FOO
=> FOO=third

The FOO=bar cmd form will really set FOO=bar in the environment of cmd, but a command like docker does not automatically export its own environment into the container, but the environment vars have to be added explicitly with the -e switch.

Again, a more straightforward demo would be:

FOO=before
FOO=after env - FOO=$FOO printenv FOO
=> before